Help us understand the problem. What is going on with this article?

【初学者向け】セキュリティ対策入門②〜SQLインジェクション編〜

前提

確認環境

以下と同様です。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

本シリーズの目的

以下と同様です。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

本記事の目標

SQLインジェクションの概要、原因、対策について理解することです。

本記事を読み進める上での必要事項

以下の内容を終えていることです。
【初学者向け】セキュリティ対策入門⓪〜環境構築編〜

また、DB及びテーブルの作成ができることと、プログラミング言語を用いてDBにアクセスする処理の流れをおおまかに理解していることです。

概要

SQLインジェクションとは

不正にSQL文を実行させることです。エンドユーザが入力した内容を元にSQLを実行するようなWebアプリケーション全般で行われる可能性があります。

これだけだとわかりにくいと思いますので実際に見てみましょう。

実際に体験してみよう

リポジトリ更新

【初学者向け】セキュリティ対策入門⓪〜環境構築編〜投稿時から本記事投稿の間にリポジトリを更新しているので、以下コマンドを参考にローカルリポジトリを更新しておいてください。

cd tutorial-php-security
git pull origin master

また、docker-compose.ymlも更新されているのでDockerコンテナ起動時は以下のように--buildを付与して起動を行ってください。

docker-compose up -d --build

DB準備

今回はDBを使うので、そのあたりの準備を行っていきます。

http://localhost:8888

にアクセスしてログインしましょう。

そしてtestという名前のDBを作りましょう。

次に以下のようなuserテーブルを作成しましょう。

スクリーンショット 2020-01-15 22.12.40.png

ブラウザアクセス

http://localhost:8080/sql_injection/bad.php?name=j&address=kanagawa
にアクセスしてみましょう。

『データが作成されました。』と表示されたら成功です。
phpMyAdminを見てみるとレコードが1件追加されていることが確認できると思います。

ソースコードはtutorial-php-security/www/html/sql_injection/bad.phpにあります。

tutorial-php-security/www/html/sql_injection/bad.php
<?php

// 略

$name = ($_GET['name']) ? $_GET['name'] : '';
$address = ($_GET['address']) ? $_GET['address'] : '';

// 略

でクエリストリングスを取得し、その値を使って

tutorial-php-security/www/html/sql_injection/bad.php
<?php

// 略

try {
    $db = getDb();
    $stmt = $db->prepare("INSERT INTO user(name, address) VALUES('{$name}', '{$address}')");
    $stmt->execute();
    echo 'データが作成されました。';
} catch(PDOException $e) {
    echo $e->getMessage();
}

userテーブルにレコードを挿入する処理が記載されています。

では次に

http://localhost:8080/sql_injection/bad.php?name=namebadtest&address=');DELETE FROM user;--
にアクセスしてみましょう。

phpMyAdminを見てみるとレコードが削除されてしまっていることが確認できると思います。

何が起きているか確認するために上記パラメータで生成されるSQL文を解説します。

INSERT INTO user(name, address) VALUES('namebadtest', '');DELETE FROM user;--')というSQL文が作られます。わかりやすいように改行も入れます。

INSERT INTO user(name, address) VALUES('namebadtest', '');
DELETE FROM user;
--')

ここまで整理すればuserテーブルのレコードが削除されてしまった理由がわかると思います。DELETE文が実行されてしまっているわけです。

SQLインジェクションの恐ろしさが伝わりましたでしょうか?
userテーブルが、とあるWebサービスの会員情報を保持しているものだとしたら会員情報が全て消えてしまいます。大きなサービスでこんなことが起きれば新聞に載ります。

原因

SQLエスケープをしていないことです。原因がシンプルですね。なので、対策もシンプルです。

対策

SQLエスケープを行うことです。

具体的に確認していきましょう。

http://localhost:8080/sql_injection/good.php?name=namebadtest&address=');DELETE FROM user;--
にアクセスしてみましょう。

今度はレコードが挿入されたことが確認できたと思います。
addressカラムには');DELETE FROM user;--という文字列が入っています。つまり、DELETE文が実行されていないわけです。

good.phpではある処理を追加しています。それを次に確認しましょう。

tutorial-php-security/www/html/sql_injection/good.php
<?php

// 略

try {
    $db = getDb();
    $stmt = $db->prepare('INSERT INTO user(name, address) VALUES(:name, :address)');
    $stmt->bindValue(':name', $name);
    $stmt->bindValue(':address', $address);
    $stmt->execute();
    echo 'データが作成されました。';
} catch(PDOException $e) {
    echo $e->getMessage();
}

DB接続について学習されている方にとっては見慣れた処理の流れになっているかと思いますが、bindValueメソッドを使っています。こうすることでSQLエスケープを行うことができます。具体的に先ほどの例で実行されるSQLを確認します。以下のようなSQL文が構築されます。

INSERT INTO user(name, address) VALUES('namebadtest', ''');DELETE FROM user;--')

わかりやすいように改行を入れます。

INSERT INTO user(name, address) VALUES('namebadtest', '
'');DELETE FROM user;--
')

2行目の'''になっているのがポイントです。SQLエスケープを行うことで実現される具体例な処理がこれです。''は単なる'という文字だと見なされ、SQL文の中で特別な意味を持って使われる'とは別ものと見なされます。

こういったことが内部で行われているため、');DELETE FROM user;--という単なる文字列としてaddressカラムに挿入されたというわけです。

参考文献

独習PHP 第3版

今回の内容は以上です。最後までご覧いただきありがとうございました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした