インジェクション
Webページからユーザー入力を受け取り、それをSQLデータベースに挿入すると、SQLインジェクションと呼ばれるセキュリティ上の問題が発生する可能性があります。この章では、この問題を回避し、PERLスクリプトなどのサーバーサイドスクリプトでスクリプトとSQL文を保護する方法をについて説明します。
インジェクションは通常、ユーザーに名前のような入力を求めるときに発生し、名前の代わりにデータベースで無意識に実行するSQL文を与えます。例えばユーザーログインの際などです。
以下の例では、名前は英数字+アンダースコアと8〜20文字の長さに制限されています(必要に応じてこれらの規則を変更してください)。
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) { $result = mysql_query("SELECT * FROM CUSTOMERS WHERE name = $matches[0]"); } else { echo "user name not accepted"; }
問題を示すためにこの抜粋について考えてください
// supposed input $name = "Qadir'; DELETE FROM CUSTOMERS;"; mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");
関数呼び出しは、name列がユーザーが指定した名前と一致するCUSTOMERS表からレコードを検索することになっています。通常の状況下では、$ nameには英数字と恐らくスペースililiaなどの文字列しか含まれません。しかしここでは、全く新しいクエリを$ nameに追加することで、データベースへの呼び出しによりハックされる恐れがあります。挿入されたDELETEは、CUSTOMERS表からすべてのレコードを除去します。
幸運なことに、MySQLを使用する場合、mysql_query()関数はクエリの積み重ねや単一の関数呼び出しでの複数のSQLクエリの実行を許可しません。クエリをスタックしようとすると、呼び出しは失敗します。
しかし、SQLiteやPostgreSQLなどの他のPHPデータベース拡張機能は積み重ねクエリを実行し、1つの文字列で提供されるすべてのクエリを実行し、深刻なセキュリティ問題を引き起こします。
SQLインジェクションの防止
PERLやPHPなどのスクリプト言語では、すべてのエスケープ文字をスマートに処理できます。PHPのMySQL拡張モジュールは、mysql_real_escape_string()関数を提供し、MySQLにとって特別な入力文字をエスケープします。
if (get_magic_quotes_gpc()) { $name = stripslashes($name); } $name = mysql_real_escape_string($name); mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");
The LIKE Quandary
LIKE難題に対処するために、カスタムエスケープメカニズムでは、ユーザー指定の ‘%’文字と ‘_’文字をリテラルに変換する必要があります。使用addcslashes() 、あなたは脱出する文字の範囲を指定することができます機能を。
$sub = addcslashes(mysql_real_escape_string("%str"), "%_"); // $sub == \%str\_ mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");