フルスタックエンジニアのノウハウ
2020.03.19    2020.03.21

プレースホルダとは何か?SQLインジェクション攻撃を回避せよ!

プレースホルダとは何か?SQLインジェクション攻撃を回避せよ!

こんにちは、徳田 啓です。
Webプログラマー歴20年、【フルスタックエンジニア マスター講座】を運営しています。(生徒数1,800名突破)

今回は「プレースホルダ」について解説します。

  • ・プレースホルダとは何か?
  • ・なぜ使う必要があるのか?
  • ・実際にはどのように使うのか?

このような疑問を解消していきます!


この記事の動画版はこちら

チャンネル登録お願いします!



SQLインジェクションという攻撃


Webサービスはインターネット上に公開され、世界中のユーザーにさらされているため、悪意のあるユーザーから攻撃を受けるリスクが常にあります。

有名な攻撃手法の1つに「SQLインジェクション」というものがあります。

  • SQLインジェクションとは、開発者の裏を突いて想定外のSQLを組み立てて、DBに対して実行させようとする攻撃方法です。


SQLインジェクションの実例(※悪用厳禁)


例えば、以下のようなSQLを実行するPHPプログラムがあったとします。


$sql = "SELECT * FROM user WHERE name='$name'";

このSQLは「user」というテーブルから、nameが一致したデータを取り出します。
検索機能などでよく使われるSQLですね。

末尾にある「$name」というPHP変数は、ユーザーが検索ボックスに入力した値が入れられます。

例えば、検索ボックスに「トクタ」と入力したら、実行されるSQLは以下のようになります。


$sql = "SELECT * FROM user WHERE name='トクタ'";

これが、開発者が想定する「正常なSQL」です。


しかし、もし検索ボックスに「';DELETE FROM user--」と入力されたらどうでしょう。

実行されるSQLはこうなります。


$sql = "SELECT * FROM user WHERE name='';DELETE FROM user--";


冒頭の「';」によって、SELECT文が終了されてしまい、続いて「DELETE FROM user」という新しいSQLが実行されてしまいます。

末尾の「--」はSQL上のコメントという意味なので、それ以降の文は無視されます。

  • つまり、開発者の全く想定しない「DELETE FROM user」(userテーブルの全データ削除)という命令が実行出来てしまうのです。

このように、ユーザーから入力された値を直接SQLに結合してしまうと、万が一悪意のあるユーザーによって不正な値が入力された場合、想定外のSQLが実行されてしまう恐れがあります。

このような攻撃手法を「SQLインジェクション」と言います。

だから絶対に、SQL文の中に直接PHPの変数を書いてはいけません。


プレースホルダを使えばOK


そこで登場するのが「プレースホルダ」という仕組みです。

プレースホルダは、上記のようなSQL文の中の「変動する箇所」に使用します。

プレースホルダを使って指定しておけば、その部分はあくまで「値」として処理され、万が一不正な値が入力されても、SQL命令に関わるような「特殊文字」は無効化(エスケープ処理と言います)されるため、SQL文として実行されることはなくなります。

入力された値を1つ1つ自分でチェックしてエスケープしても良いのですが、プレースホルダを使った方が漏れがなく安全です。

  • SQL文の中で「変動する箇所」には必ずプレースホルダを使いましょう。


プレースホルダの実際の使い方(ソース付き)


プレースホルダを使うための手順は2つです。

  • ①SQL文の変動箇所をプレースホルダ(:で始まる代替文字列)で指定する。
  • ②bindValueで実際の値をプレースホルダにバインドする。


先ほどのSQLの例で説明すると、

①まず、このように変動箇所を「:で始まる代替文字列」で指定しておきます。


$sql = "SELECT * FROM user WHERE name=:name";

なお、型の判定もプレースホルダが行ってくれるので、文字列カラムの場合でもシングルクォーテーションは不要です。この点もソースコードが見やすくなるので良いですね!

  • 現場のコツ
  • プレースホルダの名前はカラム名と同じにしておくと分かりやすいのでオススメ!


②次に、プレースホルダに実際の値を「バインド」します。

これには「bindValue」というメソッドを使います。

bindValue('プレースホルダ名', '実際にバインドするデータ', 'データの型');


bindValue(':name', $name, PDO::PARAM_STR);

型の指定は、あらかじめ用意されている設定値から選択します。

よく使うのは以下のような型です。

  • 【文字列型の場合】PARAM_STR
  • 【数値型の場合】PARAM_INT
  • 【ラージオブジェクト(画像データなど)の場合】PARAM_LOB
  • 【NULLの場合】PARAM_NULL


まとめ


  • プレースホルダは「SQLインジェクション対策」のために使う。
  • SQL文の中で「変動する箇所」には必ずプレースホルダを使う。
  • プレースホルダはカラム名と同じ名前にしておくと分かりやすい。

攻撃を未然に防ぐプログラミングが出来るフルスタックエンジニアを目指していきましょう!

なお、PHPからデータベースを操作する手順については、以下の記事で詳しく解説しているのでこちらも併せて学んでみてください。

関連記事

PHPからデータベースを操作する手順


おすすめ記事
無料メルマガ配信中