Sql-injection

提供:Dev Guides
移動先:案内検索

SQL-インジェクション

Webページを介してユーザー入力を取得し、それをSQLデータベースに挿入すると、* SQLインジェクション*と呼ばれるセキュリティの問題が発生する可能性が高くなります。 この章では、これを防ぎ、PERLスクリプトなどのサーバー側スクリプトでスクリプトとSQLステートメントを保護する方法について説明します。

通常、インジェクションは、名前などの入力をユーザーに要求すると発生します。名前の代わりに、ユーザーが知らないうちにデータベースで実行するSQLステートメントを提供します。 ユーザーが提供したデータを決して信頼せず、検証後にのみこのデータを処理します。原則として、これは Pattern Matching によって行われます。

以下の例では、 name は英数字とアンダースコアに制限され、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}'");

関数呼び出しは、名前列がユーザーが指定した名前と一致するCUSTOMERSテーブルからレコードを取得することになっています。 通常の状況では、 $ name には英数字と、おそらく文字列iliaなどのスペースのみが含まれます。 しかし、ここでは、まったく新しいクエリを$ nameに追加することにより、データベースへの呼び出しが災害に変わります。挿入されたDELETEクエリは、CUSTOMERSテーブルからすべてのレコードを削除します。

幸いなことに、MySQLを使用している場合、* mysql_query()*関数は、単一の関数呼び出しでクエリのスタックまたは複数のSQLクエリの実行を許可しません。 クエリをスタックしようとすると、呼び出しは失敗します。

ただし、 SQLitePostgreSQL などの他のPHPデータベース拡張機能は、スタッククエリを喜んで実行し、1つの文字列で提供されるすべてのクエリを実行し、深刻なセキュリティ問題を引き起こします。

SQLインジェクションの防止

PERLやPHPなどのスクリプト言語では、すべてのエスケープ文字をスマートに処理できます。 PHPのMySQL拡張機能は、MySQLに特殊な入力文字をエスケープする関数* mysql_real_escape_string()*を提供します。

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT *FROM CUSTOMERS WHERE name='{$name}'");

LIKE Quandary

LIKEの難題に対処するには、カスタムエスケープメカニズムでユーザー指定の '%'および '_'文字をリテラルに変換する必要があります。* addcslashes()*を使用します。これは、エスケープする文字範囲を指定できる関数です。

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
//$sub == \%str\_
mysql_query("SELECT * FROM messages
   WHERE subject LIKE '{$sub}%'");