WebEngine

だらだらと綴る技術系メモ

SQLインジェクション対策の一歩としてプレースホルダを利用する

そもそもSQLインジェクションとは?

悪意を持ったユーザが入力フォームなどにSQLを打ち込んで、不正に データベース(以下DB)にアクセスすること。XSSクロスサイトスクリプティング)に次いで 有名な攻撃手法とも言われます。
この攻撃を受けると・・・

  • DB内部の情報が許可したユーザ以外の人物に取得される。
  • DB内部のデータが変更させられる。
  • 認証を回避される(IDとパスワードなしでログインされるなど)

などの被害を受けます。DBは個人情報を扱うことが多いので、 公開するアプリケーションは必ずチェックしなければならない項目の 一つです。


プレースホルダには2種類ある

動的プレースホルダと静的プレースホルダです。なにが違うかと 言うと・・・

  • 動的 > 値のバインドをアプリケーション側で実行
  • 静的 > 値のバインドをDB側で実行

バインドとは、「割り当てる」という意味です。
よくわからないという方はとりあえず静的を選択しましょう。簡単に言うと、 静的プレースホルダは、プレースホルダの状態でSQL文がDBへ送られるので、あとから SQL文が変更される可能性が減るのです。

静的プレースホルダの設定の仕方

※ ここではMySQL、かつPDOで接続する場合について説明します。

プレースホルダの設定は、デフォルトで動的になっています。なので、 動的を使用する場合には、特に設定の必要はありません。
静的プレースホルダを使用する場合は、下記のようにします。

PDO::ATTR_EMULATE_PREPARES => false

ほかの設定とまとめたい場合は、こういう書き方もできます。

$pdo = new PDO(
  "mysql:host=localhost; dbname=hogehoge",
  "username",
  "password",
  [
    PDO::ATTR_EMULATE_PREPARES => false
  ]
);


値のバインドの仕方

ここでは実用性を考慮して関数にしてみました。引数で渡された$idNumberと tablenameのidで一致するものがあれば、すべて取り出して$infoに入れるという ものです。最終的には情報の入った$infoを返します。

function searchID($idNumber) {
  $stmt = $pdo->prepare('SELECT * FROM tablename WHERE id = ?');
  $stmt->bindValue(1, $idNumber, PDO::PARAM_INT);
  $stmt->execute();
  $info = $stmt->fetchAll();
  return $info;
}

見てのとおり、「?」の部分に値がバインドされます。バインドの指示を出しているのは次の行。

$stmt->bindValue(1, $idNumber, PDO::PARAM_INT);

最初の引数が何番目の「?」かという情報。2番目の引数がバインドする値、3番目が 数値か文字列か判別する引数です。例ではIDなので数値を採用しています。文字列は、

PDO::PARAM_STR

と指定します。
注意すべきなのが、何番目の「?」か、というところです。プログラミングに慣れている人 は「最初なら0じゃないか?」と思われるかもしれませんが、1からの指定になります。