第7章 エコーバック対策
スクリプト注入: #1 対策
スクリプト注入
スクリプト注入(いわゆるクロスサイトスクリプティング)は、HTMLコンテンツを通じて被害者のブラウザに悪意のスクリプト(主にJavaScriptのコード)が入り込み、ブラウザの内側からセキュリティ侵害が起こる問題である。
攻撃者がHTMLコンテンツにスクリプトを埋め込むやり方には多様なものがあり、その話題については別途「スクリプト注入: #2 攻撃の解説」を見られたい。
スクリプト注入の被害を受けるケース
例えば、スクリプト注入による利用者が被害を受けるケースには次のものがある。
- 正規サイトのページにあるリンクを書き換えられて不正サイトのページを呼び出してしまう
- 偽のページが表示され、利用者のパスワード等が奪われる
- ログイン前に、セッションIDを搬送するCookieを植え付けられ、利用者のセッションが乗っ取られる
- ログイン中に、セッションIDを搬送するCookieの値が攻撃者に知られ、セッションが乗っ取られる
- DOM(DocumentObjectModel)のAPIを通じてHiddenの情報を盗み出されてしまう
- TRACEメソッドが利用可能であることを悪用されて、HTTP要求の内容を盗み出されてしまう。例えば、Basic認証のパスワード
スクリプト注入の手口
利用者が被害を受けるスクリプト注入を使った侵害の手口は、HTMLコンテンツ内にスクリプトを埋め込むという操作を行う。これは、プログラマが用意したサーバ側のプログラムが、ブラウザから入力された値をそのままブラウザへの出力に使用してしまうことを悪用するためである。例えば、次のものがある。
- テキスト部分に直接タグを挿入する
- 引用符と>を用いタグ属性値から脱出して<script>タグを挿入する
- コメント終了記号を用いHTMLコメントから脱出して<script>タグを挿入する
- javascript:等スクリプトを起動するスキームを用いた文字列をタグのURL属性の値として与える
例 <img src="javascript:..."> - expression()を用いてスタイル中にスクリプトを記述する
例 <div style="...;z:expression(...);..."> - タグのイベントハンドラ属性内の文字列定数'xxx'から脱出してスクリプトを記述する
例 <span onmouseover="a='...'">
↑
';document.cookie='jsessionid=BAD :悪意のスクリプト - <script>...</script>の内側の文字列定数'xxx'から脱出してスクリプトを記述する
例 <script>id='...'</script>
↑
';document.cookie='jsessionid=BAD :悪意のスクリプト
上記手口の例や詳しい情報は、「スクリプト注入: #2 攻撃の解説」に掲載している。
スクリプト注入対策
スクリプト注入攻撃は、攻撃者が送り込んでくる文字列がHTMLドキュメントの一部となったときに、それがスクリプトとして解釈される構文を形成することにより成立する。
したがって、スクリプト注入対策は、これを阻害することである。
(1) 特定の特殊記号のエンティティ表現への置換
対策内容
プログラム中のデータをHTMLドキュメントに出力する際、次の特殊文字の置換を行う。
データの中の文字 | HTMLに出力する文字列 |
---|---|
< | < |
> | > |
" | " |
' | ' |
& | & |
タグ(<タグ名 属性 属性 ...> や </タグ名>)でない、一般のテキストに値を書き出す場合は、次の特殊文字の置換を行って書き出すことにより、タグと解釈され得る文字列の発生を避けることができる。
この対策が一定の効果をもつ箇所
- 一般のテキスト部分。ただし<script>...</script>の内側でないこと
- タグの属性の値であって、URL、style、イベントハンドラでないもの
例 <form id="xxx"> - HTMLコメントの内側。
例 <!-- xxx -->
この対策では攻撃を防ぎきれない箇所およびケース
- タグの属性のうち、URLを記述できるもの
- タグのstyle属性
- タグのイベントハンドラ属性
- <script>...</script>の内側
- 文字セットとしてUTF-7が使用されているか、文字セットが明示されていないHTMLドキュメント
(2) プログラムが値を書き出す箇所の限定
プログラムが値を書き出すHTMLドキュメント中の箇所が限定できる場合
対策内容
次の箇所にはプログラムから動的に値を書き出さない。
- URLを値として持ち得るタグ属性値 href= src= 等
- タグのstyle属性値 style=
- タグのイベントハンドラ属性値 onload= onmouseover= 等
- <script>...</script>の内側
適用できないケース
ただし、アプリケーションによっては何らかの識別子を<script>...</script>の内側等に文字列定数 'xxx' の形で埋め込む必要に迫られることもあり得る。
そのような場合は以下の要注意箇所への出力を行う必要に迫られている場合の対策を実施する。
- 解説
- URLを値として持ち得るタグ属性値、style属性値、イベントハンドラ属性値においては、<script>等のタグを書かなくてもスクリプトを記述し動作させることができる。
タグ属性値の中で用いられたエンティティ表現('等)は、それが表す特殊記号そのものとして扱われる。すなわち、置換を行ってもJavaScriptプログラムの意味を失わせることにならず、スクリプト実行を阻害できない。
要注意箇所への出力を行う必要に迫られている場合
そのような場合は、値を書き出す箇所への文字列埋め込みを慎重に行う。
具体的には、次のような対策を行う。
対策内容
- URL属性値
URLを値として持ち得るタグ属性値としてプログラムから動的に値を与える場合は、その属性値の先頭が必ず次のいずれかではじまるようにする。- 「http://」という文字列
- 「https://」という文字列
- 「/」を先頭あるいは途中に含むディレクトリパス
- style、イベントハンドラ、<script>...</script>の内側
次の箇所にプログラムから動的に値を与える場合、- タグのstyle属性値
- タグのイベントハンドラ属性値
- <script>...</script>の内側
- 引用符(「'」「"」「`」)
- セミコロン(「;」)
- コロン(「:」)
- 括弧(「(」「)」) 等
(3) HTMLデータの排除
入出力データとしてタグを含むHTMLデータを扱わずに済む場合
対策内容
Webアプリケーションの入出力データとしてタグを含むHTML文字列を扱わない。
適用できないケース
ただし、掲示板、ブログ、ショッピングカタログ構築キット等、HTMLタグを含む文字列データの取り扱いが不可避のアプリケーションもあり得る。
その場合は以下の入出力データとしてタグを含むHTMLデータを扱う必要にせまられている場合の対策を実施する。
入出力データとしてタグを含むHTMLデータを扱う必要に迫られている場合
そのような場合は、HTMLデータからのスクリプトを排除する。 具体的には、次のような対策を行う。
対策内容
タグを含むHTMLドキュメントまたはその一部をアプリケーションの入出力データとして取り扱う場合、入力されたHTMLドキュメントを構文解析し、スクリプトを含んでいる場合データとして受け付けないか、スクリプトを削除してから使用する。
(4) 文字セットの明示
対策内容
WebアプリケーションがHTMLドキュメントを内容とするHTTPレスポンスを送出する際には、必ず使用文字セットを明示するようにする。
- HTTPレスポンスヘッダに記述する場合:
Content-Type: text/html; charset=文字セット名> - HTMLドキュメント内に記述する場合;
<meta http-equiv="Content-Type" content="text/html; charset=文字セット名">
この対策を適用すべきとき
上記(1)を実施する際はこの(4)も併せて行う。
- 解説
- なんらかのエンコード形式を用いることにより、入力検査や特殊記号の置換措置を迂回できる場合がある。
例えば、 UTF-7 では、記号 < は +ADwA- のように表記できる。
Webアプリケーションが、文字セットの種類を(Content-Typeのcharsetで)明示しないまま、ブラウザにHTMLドキュメントを送信している場合、ブラウザによっては UTF-7 エンコード形式と見なせる文字列を自動判別してデコードし、別の文字として解釈するおそれがある。
対策漏れに注意
スクリプト注入脆弱性は、Webアプリケーションから根絶することが必ずしも容易でない。なぜなら、アプリケーションプログラムには入力データをエコーバックする場面が多く存在し、容易に対策漏れが起こるからである。
プログラムがHTMLドキュメント内に値を出力するあらゆる場面に注意を払う必要がある。
可能ならば、特定の特殊記号がエンティティ表現に自動で変換される出力APIを用意して、それ以外の出力APIを使わない等のコーディングルールを設け、ソースコードを記述する。