インジェクション攻撃とは、不正な入力によりサーバーを誤動作させる攻撃手法である。
概要
商用サイトを中心として、Webページには一般ユーザーからの入力を受け付けるものも多い。こういったページはユーザーからの入力をサーバーが受け取った後、入力情報を元に適切な処理が行われる仕組みになっている。
ところがサーバーに脆弱性があると、入力情報の中にコンピューターに対する命令と解釈される文字列を埋め込むこと(Code injection)によってサーバー側が意図していない動作を行わせることができる。これがインジェクション攻撃である。
文字列に「文字列の終了を表す表現」を埋め込んだ後に、実行させたい命令文につなげるというのが大まかな手口になる。もう少し具体的なイメージを掴みたい人は下記の9分40秒あたりから12分過ぎまでを参照のこと。
分類
SQLインジェクション
SQLはデータベースサーバー用言語のデファクトスタンダードに近い存在である。SQLインジェクションではSQLとして解釈される入力を用いて攻撃を行う。一般ユーザーの入力はSQL命令に組み込まれる形でデータベースサーバーに渡されることが多いので狙われやすい。
データベースサーバーには各ユーザーの個人情報や運営企業が他社との差別化のために苦労して集めたデータなど大事な情報が詰まっていることが多い。そこから任意の情報が読み出されたり、書き込まれたり、ひどい場合は全部抜き取られた上で消去されたりする危険もある。
NoSQLのデータベースサーバーを標的にした攻撃も存在するので、SQLでなければ安心ということではなく、データベースサーバーは狙われやすいと考えておいた方が良い。
OSコマンドインジェクション
SQLではなく、OS用のコマンドを入力に埋め込む方法。ユーザーの入力がOSに渡される仕様のサーバーというのは少ないはずだが、もし実行されるとOSそのものが乗っ取られ、OS上で動くサーバープログラムに過ぎないデータベースサーバーが乗っ取られたときより被害は大きい。
HTTPヘッダインジェクション
攻撃者が直接入力を行わないケース。不正な入力データを送信するリンクを被害者にクリックさせて、HTTPヘッダに入力内容が反映されるサイトで不正な内容を表示させる。
ヘッダーにはCookieの扱いに関する命令を含めることが出来るため、被害者のCookieを変更することも可能。他にはヘッダーに続けて本文まで偽造することも可能である。
メールヘッダインジェクション
一般ユーザーから「問い合わせ」ページなどに入力があると自動的にメールで管理者や担当者に通知する仕様になっているサーバーは多い。この際、「件名」の入力がメールの"Subject:"の行に使用されるといったように、入力がそのままメールヘッダ領域に反映される場合に攻撃対象になる。
メールヘッダインジェクションでは上記「件名」の欄に改行を入れ、その後にメールヘッダとして解釈される任意のコードを挿入する。たとえば"Bcc:"を挿入するとスパムメールの送信に用いることができる。
HTMLインジェクション
一般ユーザーの入力内容確認のためにユーザー入力全文を表示するサイトは多いが、ここにHTMLと解釈される文字列を埋め込むと、不正な入力確認画面を表示できる。
HTMLには<script>タグでJavaScriptを埋め込んだり<iframe>で別のサイトを表示できたりすることを考えると、様々な被害が考えられる。クロスサイトスクリプティング攻撃(XSS)などに使用される。
対策
一般ユーザーからの入力は疑ってかかるのが基本である。クライアント側のコードは改造可能なので原則としてサーバー側で対策を行う。
入力制限
入力欄に、処理系で文法上の意味を持つ文字や記号の入力を禁止する。あるいは、サーバー側で想定している文字列の入力のみを許可する。
エスケープ処理
大抵の処理系は、文法上意味のある文字(記号)を、文字列内で文法上の意味を持たないただの文字として使用するためのエスケープという記法が用意されている。
ユーザーからの入力にインジェクション攻撃を意図した文字列があったとしても、処理系に渡す前にエスケープ処理すれば、文法上の解釈を受けることなくただの文字として仕様通り処理される。サニタイズとも呼ばれる。
エスケープ処理を1回余計にやってしまって、「>」が「>」になるといったようにエスケープ処理が残ったまま表示されることがあるのはご愛嬌。
コンパイル
スクリプト言語処理系だからユーザーの入力が命令として解釈される。コンパイルしてバイナリにしてしまえばユーザーが入力した文字列とコンピューターへの命令が混ざることはない、というコンセプト。
SQLではプリペアドステートメントと呼ばれる。
関連動画
関連リンク
関連項目
おまけ1: SQLインジェクションの実演
- Google Colaboratoryを開く
- 「ファイル」メニューの「ノートブックを新規作成」をクリック
- 「+ コード」ボタンをクリックしてセルを用意
- 下記のコードをセルにコピペ
import textwrap f = open("init.sql", 'w') f.write(textwrap.dedent("""\ -- -*- coding: utf-8; mode: sql; sql-product: sqlite; -*- DROP TABLE IF EXISTS emp; CREATE TABLE emp(eid INTEGER PRIMARY KEY, ename TEXT); INSERT INTO emp(ename) VALUES ('のぶお'); INSERT INTO emp(ename) VALUES ('たけし'); INSERT INTO emp(ename) VALUES ('ひろゆき'); SELECT * FROM emp; """)) f.close() !sudo apt-get install -y sqlite3 !sqlite3 test.db < init.sql while True: f = open("append.sql", 'w') f.write(textwrap.dedent("""\ -- -*- coding: utf-8; mode: sql; sql-product: sqlite; -*- INSERT INTO emp(ename) VALUES ('{}'); SELECT * FROM emp; """).format(input("追加する名前: "))) f.close() !sqlite3 test.db < append.sql
- 「▶」ボタンをクリック
- 「追加する名前」の入力欄に適当な名前を入力してエンター。この手順を何度か繰り返し、入力した名前が名簿に追加されることを確認する
- 「追加する名前」の入力欄に
しげたか'); DELETE FROM emp WHERE ename IN ('ひろゆき
をコピペしてエンター
おまけ2: HTMLインジェクションの実演
ニコニコ大百科:グラフ機能のダウンロード版(サポート終了済み)にはHTMLインジェクション攻撃が可能である。といってもダウンロード版なので、自分で自分にインジェクション攻撃できるだけであり、特にセキュリティ上の問題はない。ユーザーが色以外も指定できたら何か面白いことが出来ないかなと思っていたのでこれは仕様である。
手順
- スタンドアロン用のダウンロード版をコピペしてテキスト形式で保存する。
- ウィルスチェックは自己責任で。ソースコードから自分でビルドしてもいいのよ。
- 保存したファイルをブラウザで開く。
- ダウンロード版は色指定の文字列が無修正で出力に反映されるようになっている。 ← ここが脆弱性。
- 「データ入力欄」に後述のデータを入力して「変換」ボタンを押す。
- なんということでしょう。直線しか描画できないはずのニコニコ大百科:グラフ機能で塗りつぶされた円が出力されました。
入力
3行目のred(太字)は仕様通りの色指定方法だが、その後にHTMLの<div>要素の一部として認識される不正なコード(緑字 + 赤字)が追加されている。
0.0, 0.0
170.0,0.0
300, 80.0,red; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div><div style="background: #fc9; border-radius: 40px; width: 80px; height: 80px
500.0, -110.0
出力
記事にある使用例と比べると、本来直線しか出力する機能がないのに、塗りつぶされた円が出力されているのがわかる。
HTMLソースで見ると下記のようになっている。緑字 + 赤字が不正に追加された部分で、入力の不正部分と完全に一致している。
<div><div style="border: 1px solid green; height: 150px; width: 500px;"></div><div style="border: 1px solid green; height: 150px; width: 500px;">
<div style="height: 1px; width:170.0000px; background-color: red; transform: rotate(0deg); margin: -1.0000px 0 0 0.0000px;"></div>
<div style="height: 1px; width:153.0000px; background-color: red; transform: rotate(-32deg); margin: -41.0000px 0 0 158.5000px;"></div>
<div style="height: 1px; width:276.0000px; background-color: red; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div><div style="background: #fc9; border-radius: 40px; width: 80px; height: 80px; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div>
</div></div>
解説
正規 | <div style="height: 1px; width:276.0000px; background-color: red; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div> |
---|---|
不正 | <div style="height: 1px; width:276.0000px; background-color: red; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div><div style="background: #fc9; border-radius: 40px; width: 80px; height: 80px; transform: rotate(44deg); margin: 54.0000px 0 0 262.0000px;"></div> |
正規の入力ではred(太字)で色指定を受けた単一のdiv要素(青字)であるが、前述の不正な入力を受けると、
- 不正入力の前半(緑字)により、正規のdiv要素が正常に終了する。
- 不正入力の後半(赤字)により不正なdiv要素が開始される。
- 2.は、正規のdiv要素を終了するはずであった部分(後半の青字)とつながり、不正なdiv要素が正常に終了する。
という手順を踏んで、不正なdiv要素(こちらを参考にした円を出力するHTML)が追加されたのである。
対策例
ゲームアツマール版のニコニコ大百科:グラフ機能には対策が施されており、前述の入力に対しては「不正な色文字列です。」と出力される。
- 3
- 0pt