1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SQLインジェクションの危険性とその対策について

Last updated at Posted at 2021-05-05

SQLインジェクションとは

Webアプリケーションでは様々な情報をデータベースに保存して管理します。このデータベースを操作するための言語としてSQLが使用されます。 SQLインジェクションは悪意あるユーザがサイトに不正な内容を入力し、データベース上で意図しないSQL文が実行されてしまうことです。 このままではイマイチわかりにくいので次に具体例を紹介します。

SQLインジェクションの具体例

userテーブルの中から名前が'tarou'というレコード取得するとき以下のSQL文を作成します。
SELCT * FROM user WHERE name = 'tarou';

'tarou'の部分はユーザからの入力値とします。
名前の入力欄に『tarou』と入力されたためこのようなSQL文が作成されたわけです。
では悪意あるユーザが名前の入力欄に『' OR 'A'='A'--』と入力したらどうなるでしょうか?

SELCT * FROM user WHERE name = '' OR 'A'='A'--';

当然このようなSQL文が作られます。

WHERE以降の条件をOR演算子で無理やり条件をTRUE(真)にすることで、なんとuserテーブルの全てのレコードを取得できてしまいます!

これはまずいですね。
ちなみに--はコメントアウトで以降の文字はコメントとして扱われます。
最後のシングルクォートが邪魔なのでコメントで消しているというわけです。

SQLインジェクションの対策

ユーザIDとパスワードを受け取ってログイン処理を行うとします。

まずダメな例ですがこのようなSQL文は絶対に書いてはいけません。

// ユーザが入力した値を直接SQL文に組み込んでいる
$sqlStr = "SELECT * FROM user WHERE id = '". $param["id"] ."' AND password = '". $param["password"] ."'";

$stmt = $db->prepare($sqlStr);
$stmt->execute(); // SQLを実行

ユーザが入力した値を文字列連結して直接SQLを組み立てていますが、これだとSQLインジェクションの標的になります。
悪い人がパスワードに『' OR 'A'='A'--』を入力すればログインされてしまいます。
ユーザが入力した値で直接SQLを組み立てることは絶対にしてはなりません。

ではどうしたら良いのかといいますとプレースホルダを使用します。
プレースホルダを使用したSQL文は以下のようなコードです。

// プレースホルダを利用
$sqlStr = "SELECT * FROM user WHERE id = ? AND password = ?";

ユーザの入力値が入る予定の場所に?が入っていることが確認できます。
この?がプレースホルダです。
プレースホルダによるSQL文の組み立てはパラメータ部分をこの?のような記号で示しておき、後からデータベース上で実際の値を機械的な処理で割り当てます。
プレースホルダを使用してSQLを実行するには以下のコードのようにします。

// プレースホルダを利用
$sqlStr = "SELECT * FROM user WHERE id = ? AND password = ?";

$stmt = $db->prepare($sqlStr);
$stmt->execute(array($param["id"], $param["password"])); // 値の配列を渡してSQLを実行

この割り当てる処理を「バインドする」と呼び、プレースホルダのことを「プレースホルダ変数」と呼ぶことがあります。

ちなみにプレースホルダには静的プレースホルダ動的プレースホルダがあります。
それぞれ以下の違いがあります。

  • 静的プレースホルダ(プリペアドステートメント)
    一般的には静的プレースホルダがよく使われ、プリペアドステートメントと呼ばれます。 プレースホルダのままのSQL文をデータベース側にあらかじめ送信して、実行前にSQL文の構造解析などの準備をしておく方式です。
    SQL実行の段階で実際のパラメータの値をデータベースに送信し、データベース側がバインド処理します。
    先にSQL文を確定させることで入力データによってSQL文が変更されません。

  • 動的プレースホルダ
    動的プレースホルダは静的プレースホルダと違い値のバインド処理をウェブアプリケーションのライブラリ内で実装する方式です。

この記事で紹介しているのは静的プレースホルダです。
動的プレースホルダはライブラリの実装に問題があるとSQLインジェクションを許してしまう可能性があるため、データベースが静的プレースホルダをサポートしているのであれば静的プレースホルダを使いましょう!
静的プレースホルダはSQLを準備する段階でSQL文の構文が確定し、後から構文が変化することがないので安全です。

【おまけ】SQLインジェクションの脆弱性を持っているかの判定方法(悪用厳禁)

判定方法としてサイトのSQLに組み込まれるであろう入力欄にシングルクォーテーション『``'``』を入力して送信します。もし脆弱性があるとデータベースエラーが起こります。

例えば名前の欄に『'』を入力するとこのようなSQL文ができると予想されます。

SELECT * FROM user WHERE id = ''';

SQL文は文字列をシングルクォーテーションで囲むので、もしプリペアドステートメントを使用していない脆弱性のあるサイトだと入力した『'』がSQL文として認識されます。
つまりSQL文として『'』が1つ余分になりSQLの構文が誤りになりデータベースエラーが発生します。
しかし脆弱性がないと文字列として認識されるため『'』という文字を入力しただけとして扱われデータベースエラーは起こりません。

なお、当然ですが間違っても悪用はしないでください。

1
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?