SQLインジェクション
Webアプリケーションなどが外部から受け取った値を使ってデータベースへの命令文を組み立てる処理の不備を突き、値をSQL文の一部として解釈させて、データベースを不正に操作する攻撃である。値を命令文の構造から切り離して渡すプレースホルダを使うことが根本的な対策となる。
イマシルちゃんの解説
ネットショップや会員サイトは、商品や会員の情報をデータベースに保存しているんだ。
データを探すときは、SQLというデータベース用の言語で命令文を作って問い合わせるよ。
ただ、作りに問題があると、利用者が入力した文字がその命令文にそのまま組み込まれてしまう場合があるの。
細工された入力が命令の続きとして読まれると、見せるはずのない会員情報を取り出されることもあるんだ。
ログインの確認を素通りされたり、データを書き換えられたりする場合もあって、考えただけでおそろしいね。
このように、入力を使ってデータベースへの命令を勝手に変える攻撃をSQLインジェクションというんだよ。
入力をただの値として渡して、命令の形を変えさせないことが大切なんだ。
この解説はわかりやすかったですか?
より深い解説
定義と位置付け
SQLインジェクションは、Webアプリケーションの脆弱性を利用する攻撃である。SQLはリレーショナルデータベースを操作するための言語で、データの検索・追加・更新・削除などを命令文として記述する。アプリケーションが利用者の入力を文字列として連結してSQL文を作ると、入力の内容によって命令文の意味そのものが変わることがある。
攻撃の対象は、アプリケーションの背後にあるデータベースである。XSSが利用者のブラウザでスクリプトを実行させるのに対し、SQLインジェクションはサーバ側のデータを直接ねらう。IPAの安全なウェブサイトの作り方では、取り上げる脆弱性の最初の項目として扱われている。
Webのフォームだけが入口ではない。URLのパラメータ、Cookie、HTTPヘッダー、APIのJSON、さらに一度データベースに保存された値など、SQL文の組み立てに使われる外部由来の値はすべて攻撃の入口になり得る。
命令文の意味が変わる仕組み
アプリケーションが利用者の入力をSQL文へ文字列として連結する実装では、入力に含まれる記号がSQLの構文として解釈されることがある。鍵になるのは、文字列の値を囲むシングルクォートである。
… WHERE id = '(入力されたID)' AND password = '(入力されたパスワード)'
入力値の中にシングルクォートが含まれると、アプリケーションが用意した文字列リテラルがそこで閉じたものとして扱われる。本来は「値」であるはずの続きの文字が、ORやANDといった条件式や別の命令の一部として読まれる。これにより、WHERE句の条件が常に真になるよう書き換えられたり、本来の命令に別の命令が付け足されたりする。
教科書的な例として、条件を常に成立させる ' OR '1'='1 のような文字列がよく挙げられる。認証処理で「該当する行が1件以上あればログインを認める」実装だと、この書換えによって、本来の資格情報を知らなくても認証を素通りしてしまう場合がある。
文字列リテラルの外にある数値の項目では、引用符を使わなくても条件式を注入できる。そのため、引用符だけに注目した対策では数値を扱う箇所を守れない。入力が「データ」として扱われるか「命令の構造」として扱われるかという一点が、この攻撃の本質である。
起こり得る被害
被害は、アプリケーションが使うデータベースアカウントの権限と、注入できる命令の範囲によって変わる。必ずすべてが起きるわけではないが、代表例は次のとおりである。
| 被害の例 | 内容 |
|---|---|
| 情報の漏えい | 本来表示されない会員情報や他人のデータを取り出される |
| 認証の回避 | 条件を常に真にして、認証を素通りされる |
| データの改ざん・削除 | レコードの書換えや削除、ページの改ざんが行われる |
| 権限昇格・侵入の踏み台 | 権限の設定次第ではOSコマンドの実行などにつながることがある |
画面に結果が表示されないサイトでも、条件が真のときと偽のときで応答や処理時間が変わることを手掛かりに、情報を1ビットずつ推測する手口がある。これをブラインドSQLインジェクションという。「結果が画面に出ないから安全」とは限らない。
似た攻撃との区別
名前が似た攻撃が多いため、「どこで何が意図せず解釈されるか」で区別する。
| 攻撃 | 不正な解釈が起きる場所 | 悪用するもの |
|---|---|---|
| SQLインジェクション | データベース | 値がSQLの構文として解釈されること |
| OSコマンドインジェクション | サーバのOS | 値がOSコマンドの一部として解釈されること |
| クロスサイトスクリプティング | 利用者のブラウザ | 値がHTMLやスクリプトとして解釈されること |
| HTTPヘッダインジェクション | 応答を受け取るブラウザや中継装置 | 値が改行を通じてヘッダーの構造に変わること |
いずれも「外部からの値が、本来は構造を決める側の構文として解釈される」という共通の原因を持つ。対策の考え方も、値と構造を分離する点で共通している。
値と構造を分ける根本的な対策
最も確実な対策は、SQL文の構造をあらかじめ固定し、値の部分を別に渡すプレースホルダ(バインド機構)を使うことである。値が構文として解釈される余地がなくなるため、原理的に攻撃を防げる。IPAのSQLインジェクション対策でも最初に挙げられている。
プレースホルダには二つの方式がある。
| 方式 | 値を結合する場所 | 特徴 |
|---|---|---|
| 静的プレースホルダ | データベースエンジン | 構文を先に解釈し、後から値を割り当てる。原理的に安全で推奨される |
| 動的プレースホルダ | アプリケーション側のライブラリ | ライブラリが値をエスケープして埋め込む。実装の品質に依存する |
静的プレースホルダは、ISO/JISのSQL標準におけるプリペアドステートメントに相当する。データベースエンジンがSQL文の構造を先に確定させ、後から渡された値を常に「ただの値」として扱う。このため、値にどんな記号が含まれても構文は変わらない。
SELECT * FROM users WHERE id = ? AND password = ?
? の位置へ、利用者の入力を値として個別に渡す。文字列を連結してSQL文を組み立てる方式をやめることが要点である。
どうしても文字列連結が避けられない場合は、データベースエンジンが用意するエスケープ処理を使い、リテラルを正しく構成する。ただしこの方法はデータベースの種類ごとに違い、抜けも生じやすい。OWASPのSQLインジェクション対策は、エスケープだけに頼る方法を強く非推奨とし、あらゆる状況で防げるとは保証できないとしている。
テーブル名や列名、並び順(ASC/DESC)のように、プレースホルダで渡せない部分を外部入力で決める場合は、許可リストで既定の値に対応づけ、一致しない入力を拒否する。利用者の入力でテーブル名や列名を直接指定する設計自体を見直すことが望ましい。
被害を小さくする対策
次の対策は、実装の不備が残った場合に被害を抑えるためのもので、根本的な対策の代わりにはならない。
| 対策 | 効果 | 位置付け |
|---|---|---|
| 入力値の検証 | 仕様に合わない値を受け付けない | 自由入力の項目には効きにくい |
| エラーメッセージの抑制 | データベースの種類や失敗したSQL文を画面に出さない | 攻撃者への手掛かりを減らす |
| アカウント権限の最小化 | 命令に必要な最小限の権限だけ与える | 侵入時の被害範囲を限定する |
| WAF | 既知の攻撃の特徴を持つ要求を遮断する | 一時的な緩和策 |
エラーメッセージをそのまま表示すると、データベースの種類や実行されたSQL文が攻撃者に伝わり、攻撃を組み立てやすくなる。利用者には一般的なエラー画面を返し、詳細はサーバ側のログにだけ記録する。
アプリケーションが使うデータベースアカウントには、その処理に必要な権限だけを与える。管理者権限で接続していると、侵入された場合にテーブルの削除や設定変更まで行われかねない。OWASPの資料も、ストアドプロシージャが自動的に安全なわけではなく、内部で動的にSQL文を組み立てれば同じ問題が起きると指摘している。
設計・運用での確認
- SQL文を発行する処理を、プレースホルダを使う共通の仕組みへ集約し、個別の文字列連結を減らす
- コードレビューで、入力値を連結してSQL文を作っている箇所や、ストアドプロシージャ内の動的SQLを重点的に確認する
- 脆弱性診断では、画面に結果が出ないブラインド型も含めて確認する
- データベースアカウントの権限、エラー表示の設定、監査ログの取得範囲を点検する
- WAFを導入する場合も、プログラムの修正までの一時的な緩和策として位置付ける
午後での問われ方
- 脆弱な実装と安全な実装のSQL文を比べ、なぜ入力が構文として解釈されるのかを説明させる
- プレースホルダが有効な理由を、値と構文の分離という観点で記述させる
- 静的プレースホルダと動的プレースホルダ、エスケープの違いと、どれが根本的な対策かを区別させる
- エラーメッセージの抑制やアカウント権限の最小化が、根本的な対策ではなく被害を抑える対策である理由を答えさせる
- 画面に結果が出なくても情報が漏れ得る理由を、ブラインド型の考え方から説明させる
- OSコマンドインジェクションやXSSとの違いを、不正な解釈が起きる場所に着目して整理させる