実演動画あり!SQLインジェクションとは
SQLインジェクションとは?
Webアプリケーションはサービスを提供する上で必要なデータをバックグランドでデータベースに格納しているケースが⼤半です。しかしデータベースとの連携⽅法に問題があった場合、外部からの⼊⼒によって、開発者が意図したSQL(Structured Query Language)以外の命令が実⾏されてしまうことがあります。
SQLはリレーショナルデータベースを操作するための構造化⾔語であるため、このSQL⽂が外部から変更できた場合、データベースに格納されているデータを取得する、あるいは格納されているデータを変更する、もしくは削除するなど連携しているデータベースを不正に操作することができます。
このような開発者が意図していないSQLを外部から指定できてしまう問題をSQLインジェクション脆弱性と呼び、この問題を狙った攻撃のことをSQLインジェクション攻撃といいま す。なお、SQLインジェクション攻撃は能動的攻撃(アクティブ攻撃)であるため、脆弱性の存在に気づかれた場合に即時、攻撃者からダイレクトに攻撃される危険性があります。
SQLインジェクション攻撃の仕組み
SQLインジェクションはリレーショナルデータベースと連携しているWebアプリケーションにおいて発⽣します。以下は、SQLインジェクションが発⽣する場合の⼤まかな流れとなります。
・SQLインジェクション攻撃の概要

- 攻撃者はSQLを改変する⽂字列を含んだHTTPリクエストを送信する
- 問題のあるWebアプリケーションでは、攻撃者が指定した⽂字列を含んだSQLを組み⽴てた上でデータベースにSQL命令を発⾏する
- データベースは受け取ったSQL通りの動作を⾏い結果をWebアプリケーションに応答する
- データベースからの結果を受け取ったWebアプリケーションは、その情報をもとにHTTPレスポンスを組み⽴てて攻撃者に応答する
上記のようにSQLインジェクション脆弱性が存在するWebアプリケーションでは、SQLを改変する⽂字列を含んだHTTPリクエストを受け取ると、そのままデータベースに命令として伝えてしまうため、結果として外部から不正にデータベースの操作を許すことになります。
被害事例
⽇本では2005年に某ECサイトにおいてSQLインジェクション攻撃が確認されて以来、毎年のように同問題が原因で情報漏洩などのセキュリティインシデントが発⽣しています。
以下は2022年上半期に起きたSQLインジェクションの被害事例です。
・教育関連企業の被害事例
2022年1⽉ごろに外部からのSQLインジェクション攻撃によって、およそ280,000件以上のメールアドレスが流出した可能性があることが判明しました。同社では事実発表とともにスパムメールなどによるフィッシング詐欺などへの注意喚起を⾏いました。
・ECサイトの被害事例
2022年2⽉ごろにSQLインジェクション攻撃を受けたことで、顧客のメールアドレスが
10,000件、取引先のメールアドレスが13,000件、合わせておよそ23,000名以上のメールアドレスの漏洩が引き起こされました。
・某⼤学の被害事例
2022年5⽉ごろにSQLインジェクション攻撃による不正アクセスの被害が発覚しました。この際に連絡⽤として登録されていた2,000件以上のメールアドレスが流出した疑いがあると同⼤学では公表しています。
・リサーチ会社の被害事例
2022年6⽉、同社のホームページを含む運営している複数のWebサイトに対してSQLインジェクション脆弱性が存在したため、同脆弱性をついた攻撃によって100,000件以上の会員情報の漏洩が確認されました。このインシデントにより該当サイトは5⽇間の閉鎖になりました。
上記の例に挙げたようにSQLインジェクションの被害は業種やWebサイトの規模に関係なく、脆弱性が存在すると無差別に攻撃を受けることが特徴として挙げられます。
脆弱性の解説動画
SQLインジェクションが起こる原因
Webアプリケーションからリレーショナルデータベースに発⾏するSQLを組み⽴てる際に、外部⼊⼒をそのまま⽤いてしまうことが、SQLインジェクション脆弱性の発⽣原因となります。
以下はSQLインジェクションが存在する具体的なPHPプログラムコードの例です。
・脆弱なプログラムコードの例(PHP⾔語)
<?php
$dsn = 'mysql:dbname=sample;host=127.0.0.1;';
$id = $_POST['id'];
$pass = $_POST['pass'];
try {
$db = new PDO($dsn, 'test', 'db_pass');
$sql = "SELECT * FROM users WHERE id='$id' AND pass='$pass';";
foreach ($db->query($sql) as $row) {
print($row['id'].'<br>');
print($row['name'].'<br>');
}
}
catch(PDOException $e)
{ print($e-
>getMessage());
}
?>
上記のようなプログラムコードでは、利⽤者からの⼊⼒データ(例ではPOSTデータのidや
passの値)をそのままSQL構⽂に組み込んで発⾏しているため、SQLにおいて特殊性のある
⽂字列(シングルクォートやORやANDなどの論理式、イコールなどの演算⼦)を該当パラメータの値に指定することで、SQLの内容⾃体を別の命令⽂に置き換えることが可能になります。
・開発者が意図しているSQLの例(id=user pass=user_password)
SELECT * FROM users WHERE id='user' AND pass='user_password';
idが「user」でpassが「user_password」の組み合わせにヒットするデータがある場合に該当データを取得する
・攻撃者によって改変されたSQLの例(id=user pass=’ OR ‘A’=’A)
SELECT * FROM users WHERE id='user' AND pass='' OR 'A'='A';
改変された「' OR 'A'='A」が末尾に付与されるため、該当テーブルに登録されている全件のデータを取得する命令に置き換わる
なお、SQLインジェクションについてより詳しく知りたい人は、プログラミング学習のすべてがココに「SAMURAI ENGINEER Blog」を参考にしてください。
→SQLとは?データベース言語の特徴や種類、必要性も紹介
SQLインジェクション攻撃への対策⼿法
SQLインジェクション脆弱性の混⼊を防ぐためには以下の対策を実施する必要があります。
・必須対策
Webアプリケーション内においてSQLを組み⽴てる際にはプレースホルダを使います。プレースホルダとはプログラムレベルでは記号(「?」や「:変数」など)として表記されます が、これを利⽤することでデータベースへの命令の伝わり⽅やデータベースの動作⾃体が変わります。このため、プレークスホルダを利⽤するとSQLインジェクションの問題が発⽣しなくなります。
・プレースホルダの実装例(PHP⾔語)
<?php
$dsn = 'mysql:dbname=sample;host=127.0.0.1;';
$id = $_POST['id'];
$pass = $_POST['pass'];
try {
$db = new PDO($dsn, 'test', 'db_pass');
// プレースホルダを使ってSQLの可変部分を指定する
$sql = "SELECT * FROM users WHERE id=? AND pass=?;";
// 静的プレースホルダ(プリペアードステートメント)を利⽤する
$stmt = $db->prepare($sql);
// 値をバインドする
$stmt->bindValue(1,$id);
$stmt->bindValue(2,$pass);
// 準備済みSQLを実⾏する
$stmt->execute();
foreach ($stmt->fetchAll() as $row)
{ print($row['id'].'<br>');
print($row['name'].'<br>');
}
}
catch(PDOException $e)
{ print($e->getMessage());
}
?>
なお、プレースホルダに実際の値を割り当てる処理をバインドと呼びます。
バインド処理には、プレースホルダのまま SQL ⽂を準備(コンパイル)しておきデータベースエンジンにて値を割り当てる静的プレースホルダ⽅式(別名、プリペアードステートメント)と、Webアプリケーションで利⽤するデータベース接続ライブラリ内で値をエスケープしてプレースホルダと置き換える動的プレースホルダ⽅式があります。
どちらの⽅式でもSQLインジェクション対策としては有効ですが、静的プレースホルダ(プリペアードステートメント)は、その動作原理からSQLインジェクションが発⽣することが皆無であるため、強いて⾔うならばこちらの⽅式を利⽤することが望ましいと⾔えます。(ただし利⽤しているライブラリがどちらの⽅式なのかを調べるのは⼤変なことに加えて、動的プレースホルダに問題があった場合に対処は提供元が⾏ってくれるため、それほど気にしないで選んでいただいて⼤丈夫です。)
また近年、主流になっているフレームワークを使った開発においては、基本的に ORM(Object Relational Mapping)を使ってデータベースにアクセスしますが、このORMはバックグランドでプレースホルダに変換されてデータベースにアクセスします。そのた め、基本的な利⽤⽅法で実装すればSQLインジェクションの混⼊が防げますので、利⽤するフレームワークのチュートリアルをご確認いただくことをお勧めいたします。
・推奨対策1(データベースアカウントの権限)
Webアプリケーションからデータベースに接続する際に⽤いるデータベースアカウントに対しては必要最低限の権限に絞ることで、SQLインジェクションが存在した場合に被害を最⼩限に抑えることができます。
そのため、Webアプリケーションからデータベースに発⾏するSQLを洗い出した上で、該当 SQLを実⾏するための最⼩限の権限に絞ったデータベースアカウントを⽤いることをお勧めいたします。
・推奨対策2(例外エラーの抑⽌)
例外処理などが発⽣した場合に表⽰される詳細なエラーには、利⽤しているデータベースの情報やテーブル、カラム名などSQLインジェクション攻撃に有益となる情報が含まれることがあります。そのため、前述した必須対策と併せて、エラー発⽣時に詳細なエラー内容がWebブラウザに表⽰されないように抑⽌することが望ましいと⾔えます。
・オプショナルな対策1(SQLのエスケープ処理の実装)
必須対策で挙げたプレースホルダが利⽤できない場合のみに実施します。実施する内容はデータベースの種類によって若⼲異なりますが、基本的には外部⼊⼒に対してエスケープ処理やベリデーション処理を⾏った上で、SQL構⽂を組み⽴てます。
【⽂字リテラルの処理例】
⽂字リテラルの場合は特殊⽂字をエスケープ(変換)します。
エスケープ前 | エスケープ後 | |
シングルクォート | ‘ | ‘’ |
円マーク | ¥ | ¥¥ |
【数値リテラルの処理例】
数値リテラルの場合は以下の内容以外のデータはバリデーション(チェック)してSQL構⽂に混⼊しないようにします。
内容 | |
整数 | 符号、符号なし整数、または符号あり整数 |
符号なし整数 | 1 個以上の数字 |
符号 | +(プラス)符号もしくはー(マイナス)符号 |
数字 | 0-9のいずれか |
なお、上記は⼀例のため詳細な内容についてはお使いのデータベースの仕様に合わせてください。また、エスケープ処理やバリデーション処理の実装は抜け漏れが発⽣しやすいため、可能な限り利⽤できる場合は前述したプレースホルダを利⽤するのが望ましいです。
・オプショナルな対策2(WAFの導⼊)
Webアプリケーションファイアーウォール(WAF)と呼ばれる製品を導⼊して、Webサイトを保護する⽅法です。この⽅法は⼀定の防御効果が⾒込めますが、製品を導⼊・運⽤していくのに費⽤が掛かることに加えて、理論上、すべてのSQLインジェクション攻撃を防御することができません。そのため、あくまで前述した対策が実施できない場合などに代価案として実施することが望ましい対策と⾔えます。
まずは手軽にツールで脆弱性診断
上述の対策⼿法が重要となる⼀⽅で、脆弱性が混⼊されていないかを検知する事も重要となります。そのためには脆弱性診断を受診する必要があり、SQLインジェクションの脆弱性についても脆弱性診断を通じて発⾒する事が出来ます。
脆弱性診断とは何かについて詳しく知りたい方は脆弱性診断とは(エンジニア向け)と脆弱性診断とは(⾮エンジニア向け)もぜひご参照ください。
脆弱性診断ツール「Securify」では、SQLインジェクションの脆弱性検知も対応しております。脆弱性検知やセキュリティレベルを強化したい企業様はぜひ弊社の脆弱性診断ツール「Securify」を活用ください。
無償でのトライアル実施も行っておりますので、
お気軽にお問い合わせください。