MySQL にアクセスするアプリケーションは、ユーザーによって入力されるあらゆるデータを信頼しないようにしてください。ユーザーは Web フォーム、URL、または構築されたあらゆるアプリケーションに特殊文字またはエスケープ文字のシーケンスを入力することによってコードを欺くことを試すことができます。ユーザーが 「; DROP DATABASE mysql;
」 のような入力を行なっても、アプリケーションがセキュアな状態に保たれるようにしてください。これは極端な例ですが、同様の技術を使用するハッカーに備えていない場合、結果として大規模なセキュリティーリークおよびデータ損失が発生することがあります。
よくある過ちは、文字列データ値のみ保護することです。数値データも忘れずに検査してください。ユーザーが 234
という値を入力したとき、アプリケーションが SELECT * FROM table WHERE ID=234
のようなクエリーを生成する場合、ユーザーは 234 OR 1=1
という値を入力して、SELECT * FROM table WHERE ID=234 OR 1=1
というクエリーをアプリケーションに生成させることができます。その結果、サーバーはテーブル内のすべての行を取得します。これはすべての行を公開し、サーバーに過剰な負荷がかかります。この種類の攻撃から保護するためのもっとも簡単な方法は、数値定数を囲む単一引用符を使用して、SELECT * FROM table WHERE ID='234'
とする方法です。ユーザーが余分の情報を入力すると、その情報はすべて文字列の一部となります。数値コンテキストでは、MySQL は自動的にこの文字列を数値に変換し、あとに続く数値以外のすべての文字を取り除きます。
データベースに格納されているデータが公開されているもののみであれば、保護は不要だと思われることもあります。これは正しくありません。データベース内のどの行も表示が許可されている場合であっても、サービス妨害攻撃 (前のパラグラフの技術に基づいた、サーバーにリソースを浪費させるものなど) から保護するべきです。そうしない場合、サーバーは正当なユーザーに対して応答不能になります。
チェックリスト:
厳密な SQL モードを有効にして、サーバーが受け入れるデータ値の制限を厳しくするようサーバーに指示します。セクション5.1.7「サーバー SQL モード」を参照してください。
すべての Web フォームに単一引用符または二重引用符 (「
'
」 および 「"
」) を入力してみます。何らかの種類の MySQL エラーが出る場合、すぐに問題を調査してください。動的 URL に
%22
(「"
」)、%23
(「#
」)、および%27
(「'
」) を追加して、これらを変更してみます。前の例で示した文字を使用して、動的 URL のデータ型を数値型から文字型に変更してみます。これらの攻撃や類似の攻撃に対してアプリケーションが安全であるようにしてください。
数値フィールドに、数値でなく文字、スペース、および特殊記号を入力してみます。アプリケーションはこれらを MySQL に渡す前にこれらを削除するか、またはエラーを生成します。検査済みでない値を MySQL に渡すことは非常に危険です。
データを MySQL に渡す前にデータのサイズを検査してください。
アプリケーションがデータベースに接続するときは、管理目的で使用するものとは異なるユーザー名を使用するようにしてください。アプリケーションに不要なアクセス権限を付与しないでください。
多くのアプリケーションプログラミングインタフェースには、データ値の特殊文字をエスケープする手段が備わっています。適切に使用すれば、これにより、意図とは異なる効果を持つステートメントをアプリケーションに生成させる値を、アプリケーションユーザーが入力できないようにすることができます。
MySQL C API:
mysql_real_escape_string()
API コールを使用してください。MySQL++: クエリーストリームに対して
escape
およびquote
修飾子を使用してください。-
PHP:
mysqli
またはpdo_mysql
拡張子を使用し、古いext/mysql
拡張子を使用しないでください。推奨される API は、プレースホルダを持つプリペアドステートメントのほかに、改善された MySQL 認証プロトコルおよびパスワードをサポートします。Choosing an APIも参照してください。古い
ext/mysql
拡張子を使用する必要がある場合、エスケープのために、mysql_real_escape_string()
関数を使用し、mysql_escape_string()
またはaddslashes()
を使用しないでください。これは、mysql_real_escape_string()
のみが文字セットを認識し、ほかの関数は、(無効な) マルチバイト文字セットを使用したときに「バイパスされる」可能性があるためです。 Perl DBI: プレースホルダまたは
quote()
メソッドを使用してください。Ruby DBI: プレースホルダまたは
quote()
メソッドを使用してください。Java JDBC:
PreparedStatement
オブジェクトおよびプレースホルダを使用してください。
ほかのプログラミングインタフェースも似たような機能を持っている場合があります。