ホーム > PHPセキュリティー > 7 データベース > 7-1 データベースへの攻撃と防御策 [PHPセキュリティー]
UPDATE:2017年08月09日

7-1 データベースへの攻撃と防御策 [PHPセキュリティー]

PHPセキュリティ
データベースへの攻撃と防御策 [PHPセキュリティー] | wepicks!


データベースのセキュリティーの考え方

POINT

  • データベースはリモートソース
  • データベースとの送受信データを適切にフィルタ・エスケープする

PHPから見るとデータベースはリモートソースとなります。リモートソースを起源とするデータは入力と識別して適切にフィルタを行う必要があります。入力フィルタリングに関してはこちらを参照下さい。また、リモートソースへデータを出力する際も適切にデータをエスケープする必要があります。エスケープに関してはこちらを参照下さいデータベースから取得するデータをフィルタし、データベースへ送信するデータをエスケープすることで、データベースとPHPとの間で安全なやり取りが出来ます


データベースへのアクセス認証ファイル

POINT

  • データベースアクセス認証ファイルはドキュメントルート以外に設置
  • データベースアクセス認証ファイルは config.inc などのファイル名は避ける
  • データベースアクセス認証ファイルは .php にする

データベースへアクセスする認証情報が記載されたファイルは大切な機密情報です。データベースは機密性の高い情報を扱う場合が多いので、認証情報が記載されたファイルの扱いには特に注意が必要です。このような機密性の高いファイルは必ずドキュメントルート(webサーバ上に公開するためのルートディレクトリ)以外に設置しましょう。また、ファイル名やその拡張子を config.inc のような一般的に設定情報を扱うファイルとして認識されてしまうような名前は避けましょう。また、拡張子は .php として、PHPファイルとして扱うようにしましょう


データベースへの攻撃 SQLインジェクション(SQL Injection)

POINT

  • SQLインジェクションはデータベースを不正操作する攻撃

SQLインジェクションとは、アプリケーションのセキュリティ上の脆弱性を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースから不正に情報を引き出したり、データベースを不正に操作したりする攻撃方法のことです。SQLは、データベースを操作するために一般的に使用されている言語です。

アプリケーションに入力されるデータのフィルタリング(入力のフィルタ)とデータベースに送信されるデータのエスケープ(出力のエスケープ)が適切に行われていない場合に、SQLインジェクションを受けます。

SQLインジェクションの例

以下のコードはSQLインジェクションの可能性があります。

このコードの問題点は $_POST['username'] をエスケープしていない箇所にあります。 $_POST['username'] に悪意のある値を渡すことで、アプリケーションが意図しないSQL文が実行されてしまう可能性があり、その場合、本来の機能を変えてしまうことができます。

例えば、$_POST['username'] の入力データが「yamada' —」だった場合、

となります。SQL文ではハイフンが2つ続くとそこから先はSQLコメントとして扱われますので、以下と同じ意味になります。

「–」以下の文がコメントとして扱われることになり and password = ‘$hash’ が無視されます。

このSQLが実行されるとパスワードを一切しらなくてもログインできることになってしまいます。

SQLインジェクションの例

以下のコードはSQLインジェクションの可能性があります。

このコードの問題点は $_POST['userid'] $_POST['password'] をエスケープしていない箇所にあります。

入力値が以下の場合、

SQL文は以下のようになります。

OR の後は常に真 'A=A' なので、パスワードを知らなくても常に認証されてしまいます


セカンドオーダーSQLインジェクション

SQL用の文字列をエスケープしてデータベースに登録し、そのデータをデータベースから呼び出した場合は、エスケープされていない元のデータが呼び出されることになります。このデータをエスケープしないでSQL用の文字列に使用すると、SQLインジェクションが成立してしまいます。これをセカンドオーダーSQLインジェクションを言います。SQL文字列は常にエスケープしましょう。


SQLインジェクション(SQL Injection)の防御策

POINT

  • フィルタとエスケープを適切に行うことで攻撃を防げる
  • エスケープは mysqli_real_escape_string()関数を使用
  • mysqli_real_escape_string()関数を使用するには、MySQL接続が確立されていること
  • magic_quotes_gpc が有効な場合は、最初に stripslashes() を適用する

※PHP5から mysqli_real_escape_string()の代替として、
mysqli_real_escape_string()
PDO::quote()
の使用が推奨されています。

SQLクエリを作るために使用されるデータを完全にフィルタし、フィルタされた汚染リスクのないデータを適切にエスケープすることで、SQLインジェクションのリスクはなくなります。

エスケープには、mysqli_real_escape_string()関数が利用できます。この関数は、SQL文中で用いる文字列の特殊文字をエスケープします
以下の文字の前に「\(バックスラッシュ)」を付加します。

mysqli_real_escape_string()関数を使用するには、MySQL接続が確立されていなければなりません。また、magic_quotes_gpc が有効な場合は、最初に stripslashes() を適用する必要があります。そうしないと、エスケープされているデータを更にエスケープすることになります。mysqli_real_escape_string() は % や _ をエスケープしません。 MySQL では、これらの文字を LIKE, GRANT, または REVOKE とともに用いることで、 ワイルドカードを表現します。

MySQLエスケープの例

MySQLエスケープ定義関数の例


PEAR::DBやPDO

PEAR::DBやPDOなどのバウンドパラメータやプレースホルダをサポートするデータベースライブラリを使えば、さらなるレイヤでSQLインジェクションを防ぐことが出来ます。


バインド変数の利用

POINT

  • PHPの拡張PDO(PHP Data Objects)でバインド変数の利用

バインド変数を使用することでSQLインジェクションを最適に防ぐことが出来ます。
バインド変数はPHPの拡張PDO(PHP Data Objects)で利用できるようになります。


日本語(マルチバイト文字:SHIFT-JIS、EUC-JPなど)とSQLインジェクション対策

POINT

  • マルチバイト文字の不正によるSQLインジェクションに注意
  • UTF-8にしてデータベースへ渡す

マルチバイト文字は2バイト文字などであるSHIFT-JISやEUC-JPなどです。SQLインジェクションを防止するためには「'(シングルクォート)」などの文字に対するエスケープ処理を行う必要があります。その際、日本語のようなマルチバイト文字でエスケープを行う場合、不正なマルチバイト文字に対して注意する必要があります

以下の例を考えてみましょう。

「\x97' OR A=A」文字列をエスケープ処理した場合、「予' OR A=A」と変換されることがあります。これはSHIFT-JISで発生する現象です。

「\x97'」の部分の文字列の「'」をエスケープ処理すると「\'」となり、「\x97\'」となります。
「\'」の部分もエンコードすると、「\x5C\x27」となり、全体では「\x97\x5C\x27」となります。

これを文字に戻すと、手前から「\x97\x5C」が2バイト文字として扱われて「予」となり、「\x27」が1バイト文字として扱われてしまい「'」となってしまいます。

結果として、「'」を「\'」とエスケープしたはずなのに、「'」が残ってしまうという現象が発生します。

SHIFT-JIS文字列のままデータベースに渡すことは避けましょう。
mb_convert_encodingなど使用してUTF-8などの文字列に変換することでリスクを軽減できます。

不正にエンコーディングされた文字の有無をチェックする。


データベースの暗号化

万が一データベースへ不正浸入された場合を考慮し、データ流出被害を最小限にするために機密性の高いデータは暗号化しましょう。また復号化の鍵を安全に保つ必要があります。暗号化しても秘密鍵が流出してしまえば暗号化の意味がなくなります。暗号のためのPHP標準拡張機能は mcrypt です。


SQLインジェクション対策のまとめ

POINT Webアプリケーションの対策

  • SQL用文字列を適切にフィルタする
  • SQL用文字列を適切にエスケープする
  • シフトJISの場合には1バイト文字を整理。UTF-8に変換してデータベースへ渡す
  • SQLの記述をなくすためにO/R(Object/Relational)マッピングを活用する
  • PHPやデータベースのエラーメッセージを公開しない
  • バインド機構(バインドメカニズム)を利用する

 

POINT Webアプリケーション周りの対策

  • WAF(Web Application Firewall)Webアプリケーションファイアウォール Webアプリケーションのやり取りを管理し、不正浸入を防ぐファイヤーウォール
  • IDS(Intrusion Detection System)浸入探知システム ネットワーク上の不正侵入を探知し、ネットワーク管理者に通報する
  • IPS(Intrusion Prevention System)浸入防御システム サーバーやネットワークへの不正侵入を探知するだけでなく防ぐ

 

POINT データベースの対策

  • アカウントは最小権限で運用する
  • データベースのログを適切に取得する
  • データベースの内容を暗号化する


タグ(=記事関連ワード)

日付

投稿日:2017年8月6日
最終更新日:2017年08月09日

このカテゴリの他のページ

この記事へのコメント

トラックバックurl

https://wepicks.net/phpsecurity-sql/trackback/

page top