第7章 エコーバック対策
スクリプト注入: #2 対策

スクリプトが動作する箇所

HTMLドキュメント内には、スクリプトを記述し実行できる箇所(コンテキスト)が数多く存在する。例えば次のような箇所である(図7-3)。:

  1. <script>タグ等を用いたスクリプト直接記述
  2. <script>タグ等を用いたスクリプトファイルURLのリモート参照
  3. <img src="javascript:...">等、タグのURL属性中へのスクリプト直接記述
  4. <div style="...;z:expression(...);...">等、タグのstyle属性中へのスクリプト直接記述
  5. <span onmouseover="...">等、タグのイベントハンドラ属性中へのスクリプト直接記述
  6. <a href="&{...};">等、タグ属性値におけるエンティティ参照内のスクリプト記述(Netscape 4.x で動作)

攻撃者は、スクリプトが実行されるこれらの箇所にJavaScriptプログラムの文字列をあてはめるか、何も無いところにこのような構文が作り出されるようデータを工夫して送り込んでくる。

スクリプトが動作する箇所
図7-3:スクリプトが動作する箇所

攻撃文字列

攻撃者がWebアプリケーションプログラムにエコーバックさせるべく投入してくる攻撃文字列には多くのバリエーションがありえる。主なものを挙げると、次のようなものがある。

コンテキスト1

テキスト部分に直接タグを挿入する

攻撃文字列の例:
<script>document.cookie='jsessionid=BAD'</script>

コンテキスト2

引用符と>を用いタグ属性値から脱出して<script>タグを挿入する

攻撃文字列の例:
'"><script>document.cookie='jsessionid=BAD'</script>

コンテキスト3

javascript:等スクリプトを起動するスキームを用いた文字列をタグのURL属性の値として与える

攻撃文字列の例:
javascript:document.cookie='jsessionid=BAD'

コンテキスト4

expression()を用いてスタイル中にスクリプトを記述する

攻撃文字列の例:
red;z:expression(document.cookie='jsessionid=BAD')

コンテキスト5

タグのイベントハンドラ属性内の文字列定数'xxx'から脱出してスクリプトを記述する

攻撃文字列の例:
';document.cookie='jsessionid=BAD

コンテキスト6

<script>...</script>の内側の文字列定数'xxx'から脱出してスクリプトを記述する

攻撃文字列の例:
';document.cookie='jsessionid=BAD  (コンテキスト5と同一)

スクリプト注入対策

スクリプト注入は、攻撃者が送り込んでくる文字列がHTMLドキュメントの一部となるように合成されて、その部分がブラウザによってスクリプトとして解釈される構文となることによって成立する。スクリプト注入対策は、これを阻止することである。

(1) タグを構成する記号の置換

対策内容

プログラム中のデータをHTMLドキュメントに出力する際には、攻撃文字列が混入しているおそれがあるので、タやと属性値を表現する次の記号(特殊文字)についてHTMLエンティティを表現する記法に置換する。

データの中の文字 HTMLに出力する文字列
< &lt;
> &gt;
" &quot;
' &#39;
& &amp;

この対策は、コンテキスト1とコンテキスト2に有効である。

注意事項
  • 「&」を置換するのは、他の4つのHTMLエンティティを表現する記法が「&」を用いるので、それらではない「&」を区別して解釈できるようにするためである。
  • タグの属性値を引用符「"」で囲むことを省略しないようにする。
この対策の限界

次のような箇所については、この対策は効果をもたない。

  • タグの属性のうち、URLを記述できるもの
  • タグのstyle属性
  • タグのイベントハンドラ属性
  • <script>...</script>の内側
  • 文字セットとしてUTF-7が使用されているか、文字セットが明示されていないHTMLドキュメント

(2) プログラムが値を書き出す箇所の限定

プログラムが値を書き出すHTMLドキュメント中の箇所が限定できる場合

対策内容

次の箇所にはプログラムから動的に値を書き出さない。:

  • URLを値として持ち得るタグ属性値  href= src= 等
  • タグのstyle属性値 style=
  • タグのイベントハンドラ属性値 onload= onmouseover= 等
  • <script>...</script>の内側
この対策の限界

ただし、アプリケーションによっては何らかの識別子を<script>...</script>の内側等に文字列定数 'xxx' の形で埋め込む必要に迫られることもあり得る。そのような場合は以下の要注意箇所への出力を行う必要に迫られている場合の対策を実施する。

解説
URLを値として持ち得るタグ属性値、style属性値、イベントハンドラ属性値においては、<script>等のタグを書かなくてもスクリプトを記述し動作させることができる。タグ属性値の中で用いられたエンティティ表現(&amp;#39;等)は、それが表す特殊記号そのものとして扱われる。すなわち、置換を行ってもJavaScriptプログラムの意味を失わせることにならず、スクリプト実行を阻害できない。

要注意箇所への出力を行う必要に迫られている場合

そのような場合は、値を書き出す箇所への文字列埋め込みを慎重に行う。具体的には、次のような対策を行う。:

対策内容
  1. URL属性値(コンテキスト3)
    URLを値としてもち得るタグ属性値にプログラムから動的に値を与える場合、その属性値の先頭が必ず下記のいずれかのスキームで始まるように限定する。
    • httpの場合「http://」という文字列
    • httpsの場合「https://」という文字列
    • 現在のスキームを継承する場合「/」を先頭とする絶対ディレクトリパス、および、「:」と解釈される字句を含まない相対ディレクトリパス
  2. style、イベントハンドラおよび<script>...</script>の内側(コンテキスト4、コンテキスト5およびコンテキスト6)
    下記の箇所にプログラムから動的に値を与える場合
    • タグのstyle属性値
    • タグのイベントハンドラ属性値
    • <script>...</script>の内側
    埋め込む値中に下記のような、タグ、style および JavaScriptの構文として意味をもつ特殊記号が含まれないようにする。
    • タグ(「<」「>」)
    • セミコロン(「;」)
    • 引用符(「'」「"」「`」)
    • コロン(「:」)
    • 括弧(「(」「)」) 等

(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=文字セット名">

何らかのエンコード形式を用いることにより、入力検査や特殊記号の置換措置を迂回できてしまうおそれがある。例えば、 UTF-7 では、記号 < は +ADwA- のように表記できる。Webアプリケーションが、文字セットの種類を(Content-Typeのcharsetで)明示しないままブラウザにHTMLドキュメントを送信している場合、ブラウザによっては UTF-7 エンコード形式と見なせる文字列を自動判別してデコードし、別の文字として解釈するおそれがある。

 


対策漏れに注意

スクリプト注入されうる脆弱性をWebアプリケーションから根絶することは必ずしも容易ではない。なぜならば、掲示板等のアプリケーションプログラムには入力データをエコーバックする場面は多く存在しており、対策漏れが起こりうるからである。

プログラムがHTMLドキュメント内に値を出力するあらゆる場面に注意を払う必要がある。

可能であれば、特定の特殊記号がエンティティ表現に自動で変換される出力APIを用意して、それ以外の出力APIを使わない等のコーディングルールを設けて、コーディイングするように促すのがよい。