SQLインジェクション対策でPHP(Mysqli)のプレースホルダについて調べたのでメモを残す。
まず最初に参考にしたのはIPAの「安全なウェブサイトの作り方」
下記は別冊:「安全なSQLの呼び出し方」より抜粋
このうち、静的プレースホルダは、SQLを準備する段階でSQL文の構文が確定し、あとからSQL構文が変化することがないため、SQLインジェクションの脆弱性が生じません。
それに対して、動的プレースホルダは、バインド処理を実現するライブラリの実装に問題があると、SQL構文が変化する可能性があり、SQLインジェクションの脆弱性が生じる可能性を否定できません。
静的プレースホルダというのが一番安全と言う事は分かったのでその方向で進めていきたい。
プレースホルダに対応させたい対象のプログラムはMysqli関数でDBに接続をしている。
「PHP プレースホルダ」等でググってみるとPDOでDB接続のほうが参考ページが多い印象ではあったが、すべてのプログラムをMysqliからPDOに差し替えるのは面倒に感じたので今回はMysqli関数のままプレースホルダに対応をさせたい。
色々と調べてみたもののMysqli関数でプレースホルダ対応をする場合に、動的プレースホルダとか静的プレースホルダとか明記してある参考ページが見つからなかった。
そこで、MysqliではないがPDOでの静的プレースホルダと動的プレースホルダの違いを確認しているページを見つけたので参考にした。
http://qiita.com/7968/items/7ddd59b94eb5a4fb6eaf
PDOで静的プレースホルダと動的プレースホルダをそれぞれ実行して、MySQLのログをみて確認したというもの。
つまり、Mysqli関数のプレースホルダで実行してみて、MySQLのログが上記PDOのどっちと同じになるかで静的か動的かを判断できるかと思い、やってみる事にした。
まず、phpMyAdmin上でログを見れるようにする必要があるのでこちらのページを参考に設定をした。
xampp上で試したので /xampp/mysql/bin/my.ini を編集をした。
するとmysqlデータベースのgeneral_logテーブルに一般クエリログが記録されていくとの事。
general_logテーブルの中身はこんな感じ。
では、Mysqli関数のプレースホルダを実行してみる。コードは下記のような感じでINSERTをする。いろんな参考ページをみていてどこのページから引用したのか分からなくなってしまったが、php.netに記載されているmysqli_stmtの内容と概ね一緒である。
<?php $mysqli = new mysqli('ホスト名', 'ユーザー名', 'パスワード', 'データベース名'); /* 接続状況をチェックします */ if (mysqli_connect_errno()) { printf("Connect failed: %s\n", mysqli_connect_error()); exit(); } // ここでSQL文を作成します(パラメータはありません) $stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)"); // ここでパラメータに実際の値となる変数を入れます。 // sssdのところは、それぞれパラメータの型(string, string, string, double)を指定しています。 $stmt->bind_param('sssd', $code, $language, $official, $percent); // ここで変数に値を代入しています。 $code = 'DEU'; $language = 'Bavarian'; $official = "F"; $percent = 11.2; /* プリペアドステートメントを実行します */ $stmt->execute(); // $stmt->affected_rowsでクエリ結果を取得しています。これはInsert文などで変更された行の数を返します。 printf("%d Row inserted.\n", $stmt->affected_rows); /* ステートメントと接続を閉じます */ $stmt->close(); /* 接続を閉じます */ $mysqli->close(); ?>
続いて、mysqlデータベースのgeneral_logテーブルを確認してみるとこんな感じ。
Prepareの後にExecute。参考サイトにもあるがこれは静的プレースホルダである。
Mysqli関数でプレースホルダに対応をさせると静的プレースホルダという事が分かった。逆にMysqli関数で動的プレースホルダは無理と思われる。
という訳で、安心してこの内容でMysqli関数をプレースホルダに移行していく事にした。
少し本題とは外れるが、この一般クエリログをとったらphpMyAdminが結構重くなった気がするので特に必要がなければ元に戻したほうが良いかもしれない。
またなにかあれば追記をする。