情報セキュリティ

安全なウェブサイトの作り方 - 1.5 クロスサイト・スクリプティング

概要

ウェブアプリケーションの中には、検索のキーワードの表示画面や個人情報登録時の確認画面、掲示板、ウェブのログ統計画面等、利用者からの入力内容やHTTPヘッダの情報を処理し、ウェブページとして出力するものがあります。ここで、ウェブページへの出力処理に問題がある場合、そのウェブページにスクリプト等を埋め込まれてしまいます。この問題を「クロスサイト・スクリプティングの脆弱性」と呼び、この問題を悪用した攻撃手法を、「クロスサイト・スクリプティング攻撃」と呼びます。クロスサイト・スクリプティング攻撃の影響は、ウェブサイト自体に対してではなく、そのウェブサイトのページを閲覧している利用者に及びます。

  • クロスサイト・スクリプティング

発生しうる脅威

クロスサイト・スクリプティング攻撃により、発生しうる脅威は次のとおりです。

本物サイト上に偽のページが表示される
  • 偽情報の流布による混乱
  • フィッシング詐欺による重要情報の漏えい 等
ブラウザが保存しているCookieを取得される
  • Cookie にセッションIDが格納されている場合、さらに利用者へのなりすましにつながる (脚注1)
  • Cookie に個人情報等が格納されている場合、その情報が漏えいする
任意のCookieをブラウザに保存させられる
  • セッションIDが利用者に送り込まれ、「セッションIDの固定化(脚注2)」 攻撃に悪用される

注意が必要なウェブサイトの特徴

運営主体やウェブサイトの性質を問わず、あらゆるサイトにおいて注意が必要な問題です。Cookieを利用してログインのセッション管理を行っているサイトや、フィッシング詐欺の攻撃ターゲットになりやすいページ(ログイン画面、個人情報の入力画面等)を持つサイトは、特に注意が必要です。

この脆弱性が生じやすいページの機能例
  • 入力内容を確認させる表示画面(会員登録、アンケート等)
  • 誤入力時の再入力を要求する画面で、前の入力内容を表示するとき
  • 検索結果の表示
  • エラー表示
  • コメントの反映(ブログ、掲示板等) 等

届出状況

クロスサイト・スクリプティングの脆弱性の届出件数は、他の脆弱性に比べて多くなっています。この脆弱性については、届出受付開始から2014年第4四半期までに、ウェブサイトの届出件数の約5割に相当する届出を受けています。また、ソフトウェア製品においても、この脆弱性に関して多数の届出を受けています。下記は、IPAが届出を受け、同脆弱性の対策が施されたソフトウェア製品の例です。

対策について

クロスサイト・スクリプティングの脆弱性への対策は、ウェブアプリケーションの性質に合わせ、下記の3つに分類しています。

  • 1) HTMLテキストの入力を許可しない場合の対策
  • 2) HTMLテキストの入力を許可する場合の対策
  • 3) 全てのウェブアプリケーションに共通の対策
  • 1) に該当するウェブアプリケーションの例には、検索機能や個人情報の登録等、HTMLタグ等を用いた入力を許可する必要がないものが挙げられます。多くのウェブアプリケーションがこちらに該当するはずです。

  • 2) に該当するウェブアプリケーションの例には、自由度の高い掲示板やブログ等が挙げられます。たとえば、利用者が入力文字の色やサイズを指定できる機能等を実装するために、HTMLテキストの入力を許可する場合があるかもしれません。

  • 3) は、1)、2) の両者のウェブアプリケーションに共通して必要な対策です。

1.5.1 HTMLテキストの入力を許可しない場合の対策

根本的解決

5-(i) ウェブページに出力する全ての要素に対して、エスケープ処理を施す。

ウェブページを構成する要素として、ウェブページの本文やHTMLタグの属性値等に相当する全ての出力要素にエスケープ処理を行います。エスケープ処理には、ウェブページの表示に影響する特別な記号文字(「<」、「>」、「&」等)を、HTMLエンティティ(「&lt;」、「&gt;」、「&amp;」等)に置換する方法があります。また、HTMLタグを出力する場合は、その属性値を必ず「"」(ダブルクォート)で括るようにします。そして、「"」で括られた属性値に含まれる「"」を、HTMLエンティティ「&quot;」にエスケープします。

脆弱性防止の観点からエスケープ処理が必須となるのは、外部からウェブアプリケーションに渡される「入力値」の文字列や、データベースやファイルから読み込んだ文字列、その他、何らかの文字列を演算によって生成した文字列等です。しかし、必須であるか不必要であるかによらず、テキストとして出力するすべてに対してエスケープ処理を施すよう、一貫したコーディングをすることで、対策漏れ(脚注3)を防止することができます。

なお、対象となる出力処理はHTTPレスポンスへの出力に限りません。JavaScriptのdocument.writeメソッドやinnerHTMLプロパティ等を使用して動的にウェブページの内容を変更する場合も、上記と同様の処理が必要です。

5-(ii) URLを出力するときは、「http://」や 「https://」で始まるURLのみを許可する。

URLには、「http://」や「https://」から始まるものだけでなく、「javascript:」の形式で始まるものもあります。ウェブページに出力するリンク先や画像のURLが、外部からの入力に依存する形で動的に生成される場合、そのURLにスクリプトが含まれていると、クロスサイト・スクリプティング攻撃が可能となる場合があります。たとえば、利用者から入力されたリンク先のURLを「<a href="リンク先のURL">」の形式でウェブページに出力するウェブアプリケーションは、リンク先のURLに「javascript:」等から始まる文字列を指定された場合に、スクリプトを埋め込まれてしまう可能性があります。リンク先のURLには「http://」や「https://」から始まる文字列のみを許可する、「ホワイトリスト方式」で実装してください。

5-(iii) <script>...</script> 要素の内容を動的に生成しない。

ウェブページに出力する<script>...</script>要素の内容が、外部からの入力に依存する形で動的に生成される場合、任意のスクリプトが埋め込まれてしまう可能性があります。危険なスクリプトだけを排除する方法も考えられますが、危険なスクリプトであることを確実に判断することは難しいため、<script>...</script>要素の内容を動的に生成する仕様は、避けることをお勧めします。

5-(iv) スタイルシートを任意のサイトから取り込めるようにしない。

スタイルシートには、expression() 等を利用してスクリプトを記述することができます。このため任意のサイトに置かれたスタイルシートを取り込めるような設計をすると、生成するウェブページにスクリプトが埋め込まれてしまう可能性があります。取り込んだスタイルシートの内容をチェックし、危険なスクリプトを排除する方法も考えられますが、確実に排除することは難しいため、スタイルシートを外部から指定可能な仕様は、避けることが望まれます。

保険的対策

5-(v) 入力値の内容チェックを行う。

入力値すべてについて、ウェブアプリケーションの仕様に沿うものかどうかを確認する処理を実装し、仕様に合わない値を入力された場合は処理を先に進めず、再入力を求めるようにする対策方法です。ただし、この対策が有効となるのは限定的です。例えば、アプリケーションの要求する仕様が幅広い文字種の入力を許すものである場合には対策にならないため、この方法に頼ることはお勧めできません。

対策になるとすれば、アプリケーションの要求する仕様が英数字のみの入力を許すものである場合などであり、この仕様の入力についての内容チェックはクロスサイト・スクリプティング攻撃を防止できる可能性が高いですが、この場合も、入力値の確認処理を通過した後の文字列の演算結果がスクリプト文字列を形成してしまうプログラムとなっている可能性を想定すれば、やはり完全な対策ではありません。

1.5.2 HTMLテキストの入力を許可する場合の対策

根本的解決

5-(vi) 入力されたHTMLテキストから構文解析木を作成し、スクリプトを含まない必要な要素のみを抽出する

入力されたHTMLテキストに対して構文解析を行い、「ホワイトリスト方式」で許可する要素のみを抽出します。ただし、これには複雑なコーディングが要求され、処理に負荷がかかるといった影響もあるため、実装には十分な検討が必要です。

保険的対策

5-(vii) 入力されたHTMLテキストから、スクリプトに該当する文字列を排除する。

入力されたHTMLテキストに含まれる、スクリプトに該当する文字列を抽出し、排除してください。抽出した文字列の排除方法には、無害な文字列へ置換することをお勧めします。たとえば、「<script>」や「javascript:」を無害な文字列へ置換する場合、「<xscript>」「xjavascript:」のように、その文字列に適当な文字を付加します。他の排除方法として、文字列の削除が挙げられますが、削除した結果が危険な文字列を形成してしまう可能性(脚注4)があるため、お勧めできません。

なお、この対策は、危険な文字列を完全に抽出することが難しいという問題があります。ウェブブラウザによっては、「java&#09;script:」や「java(改行コード)script:」等の文字列を「javascript:」と解釈してしまうため、単純なパターンマッチングでは危険な文字列を抽出することができません。そのため、このような「ブラックリスト方式」による対策のみに頼ることはお勧めできません。

1.5.3 全てのウェブアプリケーションに共通の対策

根本的解決

5-(viii) HTTPレスポンスヘッダのContent-Typeフィールドに文字コード(charset)を指定する。

HTTPのレスポンスヘッダのContent-Typeフィールドには、「Content-Type: text/html; charset=UTF-8」のように、文字コード(charset)を指定できます。この指定を省略した場合、ブラウザは、文字コードを独自の方法で推定して、推定した文字コードにしたがって画面表示を処理します。たとえば、一部のブラウザにおいては、HTMLテキストの冒頭部分等に特定の文字列が含まれていると、必ず特定の文字コードとして処理されるという挙動が知られています。

Content-Typeフィールドで文字コードの指定を省略した場合、攻撃者が、この挙動を悪用して、故意に特定の文字コードをブラウザに選択させるような文字列を埋め込んだ上、その文字コードで解釈した場合にスクリプトのタグとなるような文字列を埋め込む可能性があります。

たとえば、具体的な例として、HTMLテキストに、 「+ADw-script+AD4-alert(+ACI-test+ACI-)+ADsAPA-/script+AD4-」という文字列が埋め込まれた場合が考えられます。この場合、一部のブラウザはこれを「UTF-7」の文字コードでエンコードされた文字列として識別します。これがUTF-7として画面に表示されると 「<script>alert('test');</script>」として扱われるため、スクリプトが実行されてしまいます。

ウェブアプリケーションが、前記 5-(i) の「エスケープ処理」を施して正しくクロスサイト・スクリプティングの脆弱性への対策をしている場合であっても、本来対象とする文字がUTF-8やEUC-JP、Shift_JIS等の文字コードで扱われてしまうと、「+ADw-」等の文字列が「エスケープ処理」されることはありません。

この問題への対策案として、「エスケープ処理」の際にUTF-7での処理も施すという方法が考えられますが、UTF-7のみを想定すれば万全とは言い切れません。またこの方法では、UTF-7を前提に「エスケープ処理」した結果、正当な文字列(たとえば「+ADw-」という文字列)が別の文字列になるという、本来の機能に支障をきたすという不具合が生じます。

したがって、この問題の解決策としては、Content-Typeの出力時にcharsetを省略することなく、必ず指定することが有効です。ウェブアプリケーションがHTML出力時に想定している文字コードを、Content-Typeのcharsetに必ず指定してください(脚注5)。

保険的対策

5-(ix) Cookie情報の漏えい対策として、発行するCookieにHttpOnly属性を加え、TRACEメソッドを無効化する。

「HttpOnly」は、Cookieに設定できる属性のひとつで、これが設定されたCookieは、HTMLテキスト内のスクリプトからのアクセスが禁止されます。これにより、ウェブサイトにクロスサイト・スクリプティングの脆弱性が存在する場合であっても、その脆弱性によってCookieを盗まれるという事態を防止できます。

具体的には、Cookieを発行する際に、「Set-Cookie:(中略)HttpOnly」として設定します。 なお、この対策を採用する場合には、いくつかの注意が必要(脚注6) です。

HttpOnly属性は、ブラウザによって対応状況に差がある(脚注7)ため、全てのウェブサイト閲覧者に有効な対策ではありません。

本対策は、クロスサイト・スクリプティングの脆弱性のすべての脅威をなくすものではなく、Cookie漏えい以外の脅威は依然として残るものであること、また、利用者のブラウザによっては、この対策が有効に働かない場合があることを理解した上で、対策の実施を検討してください。

5-(x) クロスサイト・スクリプティングの潜在的な脆弱性対策として有効なブラウザの機能を有効にするレスポンスヘッダを返す。

ブラウザには、クロスサイト・スクリプティング攻撃のブロックを試みる機能を備えたものがあります。しかし、ユーザの設定によっては無効になってしまっている場合があるため、サーバ側から明示的に有効にするレスポンスヘッダを返すことで、ウェブアプリケーションにクロスサイト・スクリプティング脆弱性があった場合にも悪用を避けることができます。ただし、下記に示すレスポンスヘッダは、いずれもブラウザによって対応状況に差がある(脚注8)ため、全てのウェブサイト閲覧者に有効な対策ではありません。

【X-XSS-Protection】

「X-XSS-Protection」は、ブラウザの「XSS フィルタ」の設定を有効にするパラメータです。ブラウザで明示的に無効になっている場合でも、このパラメータを受信することで有効になります。 HTTP レスポンスヘッダに「X-XSS-Protection: 1; mode=block」のように設定することで、クロスサイト・スクリプティング攻撃のブロックを試みる機能が有効になります。

【Content Security Policy】

「Content Security Policy (CSP)(脚注9)」は、ブラウザで起こりうる問題を緩和するセキュリティの追加レイヤーです。その機能の一つに、反射型クロスサイト・スクリプティング攻撃を防止する「reflected-xss」があります。HTTP レスポンスヘッダに「Content-Security-Policy: reflected-xss block」のように設定することで、クロスサイト・スクリプティング攻撃のブロックを試みる機能が有効になります。

以上の対策により、クロスサイト・スクリプティング攻撃に対する安全性の向上が期待できます。クロスサイト・スクリプティングの脆弱性に関する情報については、次の資料も参考にしてください。

脚注

  1. (脚注1)
    「1.4 セッション管理の不備」で解説した「発生しうる脅威」と同じ内容です。
  2. (脚注2)
  3. (脚注3)
  4. (脚注4)
  5. (脚注5)
    W3C 勧告 HTML 4.0.1では、ブラウザに対し、文字コードを決定する場合には次の優先順位を守らねばならない、としています。
    • 1. HTTPヘッダのContent-Typeフィールドのcharsetパラメータ
    • 2. META要素で、http-equiv属性値がContent-Typeかつvalue属性の値にcharset情報があるもの
    • 3. 外部リソースを指している要素に設定されているcharset属性値
    • したがって、文字コードの指定箇所は、1.の「HTTPヘッダのContent-Typeフィールドのcharsetパラメータ」であることが望ましいと考えられます。
  6. (脚注6)
    Windows XP以前ではウェブサーバにおいて「TRACEメソッド」を無効とする必要がありました。「TRACEメソッド」が有効である場合、サイトにクロスサイト・スクリプティングの脆弱性があると、「Cross-Site Tracing」と呼ばれる攻撃手法によって、ブラウザから送信されるHTTPリクエストヘッダの全体が取得されてしまいます。HTTPリクエストヘッダにはCookie情報も含まれるため、HttpOnly属性を加えていてもCookieは取得されてしまいます。
  7. (脚注7)
  8. (脚注8)
  9. (脚注9)

CWE