京セラコミュニケーションシステム
セキュリティ事業部 副事業部長
徳丸 浩(とくまる ひろし)
Webアプリケーションのぜい弱性を示す用語として,クロスサイト・スクリプティング,SQLインジェクションといった言葉の認知度はかなり高まった。ブログ・サイトなどでも活発に議論されている。しかし,Webサイトの実態はどうだろうか。
筆者の所属する京セラコミュニケーションシステムでは昨年(2006年),ぜい弱性診断を実施したWebサイトの統計情報「2007年版 Webアプリケーションぜい弱性傾向」を発表した。これによると,パソコン向けWebサイトの48%に致命的なぜい弱性が見つかった。このうちワースト1位はクロスサイト・スクリプティングで56%,2位はSQLインジェクションで11%と,どちらもインジェクション(注入)系のぜい弱性。これらのぜい弱性を持った危険なサイトは依然として存在するのが実情である。
これらWebアプリケーションのぜい弱性があまりなくならない理由はいくつかあるが,以前は「ぜい弱性についてまったく知らない」というケースが多かったのに対して,最近は「一応知ってはいるが正しい対処方法を知らない」というケースが多くなりつつあるように感じている。本稿では,Webアプリケーションのぜい弱性のうち,「インジェクション系ぜい弱性」について取り上げ,正しい対策の方法について説明することにしたい。
インジェクション系のぜい弱性とは
Webアプリケーションのぜい弱性のうちで特に有名なSQLインジェクションとクロスサイト・スクリプティングは,命名が異なるため気付きにくいかもしれないが,実は共通の原理に基づく。したがって,原理が共通だということは,対策にも共通の原則があることにほかならない。このため,共通原理・原則を理解することにより,各ぜい弱性に対する正しい理解が容易になり,場当たり的な対策や,間違った対策をする可能性を減少させることが可能となる。
インジェクション系ぜい弱性の一般論を説明する前に,その典型例であるSQLインジェクションについておさらいをしておこう。SQLインジェクションとは,データベース・サーバーに送るSQL文を構成するパラメータにSQL断片を挿入してSQLの意味を改変し,不正な操作を実行することである。例えば図1のように,ユーザー認証の入力フォームを悪用する場合。通常は,ユーザーIDとパスワード入力からSQLを実行して,IDとパスワードの組み合わせの妥当性を確認する。ここではプログラミング言語としてはPerlやPHPを想定している。
図1 パスワード認証のSQL例
SELECT COUNT(*) FROM T_USER WHERE ID= '$id' AND PASSWD = '$passwd' |
ここで,$idや$passwdはPerlなどで変数を意味しており,実行時には変数の内容がそのまま文字列として使われる。ここで変数$passwdに,「' or 'A'='A」という文字列(前述したSQLの断片)を入力すると,SQL文は図2のようになる。WHERE句の右端が「or 'A'='A'」となっていることがお分かりいただけるだろう。これでWHERE句は常に真となり,パスワードを知らなくても固定の文字列を入力するだけで認証が通ることになる 。SQLインジェクションの例としては最も代表的な手法である。
図2 インジェクション後のSQL
SELECT COUNT(*) FROM T_USER WHERE ID= 'tokumaru' AND PASSWD = '' or 'A'='A' |
このようなことが起こるのは,プログラム中でSQLのメタ文字(特殊文字)であるシングルクォート「'」に対する処置を施していないことが原因である。SQLでは,シングルクォートを使う場合は「''」とシングルクォートを重ねる必要がある。こうした処理をエスケープ処理と呼び,怠るとこのようなぜい弱性が生じる。
以上がSQLインジェクションの原理である。これに対してクロスサイト・スクリプティング,OSコマンド・インジェクションなども,不正な文字列を混入させる点は同じ。混入させる文字列の内容と対象が異なるだけである。クロスサイト・スクリプティングは,HTMLとして表示する文字列の中にHTMLやJavaScriptを混入させる。OSコマンド・インジェクションは,シェルを起動した処理(ファイルの内容を表示するなど)のパラメータに,別のコマンドを混入するものだ。このほか主なインジェクション系のぜい弱性について表1にまとめた。
表1 インジェクション系ぜい弱性のまとめ
ぜい弱性 | コマンド | 悪用手口 | 特殊文字 |
---|---|---|---|
SQLインジェクション | SQL | SQL文の注入 | '\など |
クロスサイト・スクリプティング | HTML, JavaScript | JavaScriptなどの注入 | <>"'など |
OSコマンド・インジェクション | シェル | コマンドの追加 | |;&$`など |
HTTPヘッダー・インジェクション | HTTP | HTTPレスポンス・ヘッダーの追加 | 改行 |
メールの第三者中継 | sendmail(SMTP) | SMTPヘッダー・フィールドの追加 | 改行 |
エスケープ漏れは「バグ」
インジェクション系ぜい弱性が発生する共通原因は何か。その一つとして,アプリケーションが利用する様々なインタフェース(HTML、SQL,HTTPなど)がテキスト形式であることが挙げられる。テキスト形式なので,命令やデータ値を区別するためのメタ文字のような,しかるべき「文法」が必要になる。この文法の裏をかくのがインジェクション系のぜい弱性で,テキスト形式のインタフェースには必ずついて回る。そこで,それぞれの文法の規則にしたがってプログラム中でエスケープ処理を実施する必要がある。
これはセキュリティ上の必要性というよりは,インタフェースを利用する際の基本要件と言ってよい。エスケープ処理の漏れは,ぜい弱性というよりは単純なバグ(構文エラー)と呼んでよい。そのバグの出方の一つとして,セキュリティ上の問題,つまりぜい弱性となって現れるだけのことである。インジェクション系ぜい弱性は,テキスト・インタフェースを利用する際の不備に起因する単純なバグではあるが,これらが原因となって,セッション・ハイジャックやデータ漏えい,改ざんなど,様々なセキュリティ上の問題が発生している。
図3 Webアプリケーションの基本的な構造 [画像のクリックで拡大表示] |
Webアプリケーションのぜい弱性を検討する前提として,Webアプリケーションの構造をおさらいしておこう。Webアプリケーションは一般に,ページ間を遷移する際にプログラム(CGIなど)が起動され,その中でデータベースなどにアクセスを行う(図3)。これを,伝統的な「入力-処理-出力」モデルに当てはめると図4のようになる。
図4 「入力-処理-出力」モデルで見たWebアプリケーションの構造 [画像のクリックで拡大表示] |
図5 Webアプリケーションが利用する各種インタフェース [画像のクリックで拡大表示] |
実際には,Webアプリケーションが扱うインタフェースには,リレーショナル・データベース管理システム(SQL)やブラウザ(HTML)のほか,OSコマンド,メールなどがある。これらを取りまとめて一種の「出力」だと考えると,図5のようにまとめることが可能である。
並べてみるとわかることだが,インジェクション系のぜい弱性をなくすには,HTMLやSQLへの対応を個別に取り上げるのではなく,テキスト形式を利用するインタフェース全体像から考えを進めなければならない。また,HTMLエンコードやSQLメタ文字のエスケープは,それぞれのインタフェースの固有事情であって,そのような固有の事象をプログラム全体に散りばめてはならない。隠ぺい,ないしはカプセル化するのが正しいプログラム作法である。HTMLエンコードは表示処理の中に隠ぺいすべきだし,SQLメタ文字のエスケープはデータベース・アクセス処理の中に隠ぺいすべきである。メール送信やOSコマンドの利用などについても同様だ。
入力時の検査は本質的ではない,最適解は出力時のエスケープ
ところで、インジェクション系ぜい弱性への対策としては、伝統的に入力時の文字検査に頼っていた。具体的には,セキュリティ上問題となりやすい文字,あるいは文字列に対して,以下のような手法が使われる。
a.問題となる文字(列)を取り除く
b.問題となる文字(列)をエスケープする
c.問題となる文字(列)をエラーとする
ただ,こうした入力時の検査には問題点がある。以下で,それぞれの手法を見てみよう。
a.問題となる文字(列)を取り除く
タグ文字やクォート文字など,セキュリティ上問題となる特殊文字があれば,それらを入力文字列から除去するという方法である。狭義のサニタイジング(無害化)と呼ばれる方法である。この方法は一見すると確実性が高く,対処のためのコストが低いように見えるが,次のような問題がある。
・入力文字列を「勝手に」改変するのはアプリケーションの要件に反する
・要件として特殊文字の利用が必要な場合には使えない
・インジェクション文字は入力文字列(リクエスト)だけでなく,データベースやメールからも入ってくる
b.問題となる文字(列)をあらかじめエスケープしておく
では,問題が起こりそうな特殊文字について,あらかじめエスケープ処理を実装しておく方法はどうか。この手法も広義のサニタイジングに含める場合がある。
この手法を採用すると,アプリケーションのプログラム・ロジック中ではエスケープ済みの文字列が流れることになり,さまざまな弊害がある。例えばSQLインジェクション対策済みの文字列は,シングルクォートが二重になっているので,Webブラウザに表示する際にもそのような文字列が表示される。このようなサイトは珍しくないが,ユーザーから見れば,シングルクォートを一つしか入力してないつもりなのに二つ表示されると驚くだろう。また,ソートや印刷,メール送信などの際に文字が化けたり,ソート順が狂ったりという弊害を生むこともあり,アプリケーション要件を満たすことはできない。
c.問題となる文字(列)をエラーとする
この方法は,インジェクションの原因となる文字が入力された場合に,「利用できない文字があります」というエラー・メッセージを表示して処理を中断するものである。aやbに比べれば副作用は少ないが,特殊記号をアプリケーションで利用したい場合にはこの方法は使えない。ECサイトの住所入力欄や,ブログの投稿欄などでは特殊記号を入力したい場合もあるわけで,この入力時検査によるエラー処理もアプリケーション要件を満たせない。
このように入力時の対処はセキュリティの点からも,アプリケーション要件の点からも問題が多い。だからといって,入力時に何も対処しなくてよいというわけではない。入力時にできることとしては,入力文字列の正当性検証が挙げられる。文字種チェックや文字列長チェックといった,入力値の検証(Validation)である。一例として,郵便番号欄であれば,数字とハイフンのみで8桁以内などのチェックを行う。こうすれば,一部の攻撃は防ぐことができる。
もちろん入力値検証は,インジェクション対策にならない場合もある。任意の文字を入力可能な住所欄,掲示板のタイトルや本文などは,任意文字を許容している場合が多く,入力値検証だけでは必ずしも攻撃を防げない。入力時対処ではセキュリティ対策をしたことにはならないと考えるべきである。
そこで重要なのが,出力時,つまりHTMLやSQLなどインタフェース言語の組み立てを行う際のエスケープである。さらに言えば,インジェクション系ぜい弱性の原因であるインタフェース言語の組み立て処理そのものをアプリケーション側では実行せずに,専用のAPIを利用することが望ましい。
これらエスケープ処理は,セキュリティ対策以前に正しい処理をするために必須であり,正しいエスケープ処理がなされていれば,インジェクション系のぜい弱性も入り込む余地がなくなる。ところが,エスケープ処理にまつわる誤解などもあり,正しい対策方法は十分普及していないのが実情である。次回は,具体的な対策の方法について解説する。