XSS対策 ================================================================================ .. only:: html .. contents:: 目次 :local: .. _SpringSecurityXSS: Overview -------------------------------------------------------------------------------- クロスサイトスクリプティング(以下、XSSと略す)について説明する。 クロスサイトスクリプティングとは、アプリケーションのセキュリティ上の不備を意図的に利用し、サイト間を横断して悪意のあるスクリプトを混入させることである。 例えば、ウェブアプリケーションが入力したデータ(フォーム入力など)を、適切にエスケープしないまま、HTML上に出力することにより、入力値に存在するタグなどの文字が、そのままHTMLとして解釈される。 悪意のある値が入力された状態で、スクリプトを起動させることにより、クッキーの改ざんや、クッキーの値を取得することによる、セッションハイジャックなどの攻撃が行えてしまう。 Stored, Reflected XSS Attacks ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XSS攻撃は、大きく二つのカテゴリに分けられる。 **Stored XSS Attacks** Stored XSS Attacksとは、悪意のあるコードが、永久的にターゲットサーバ上(データベース等)に格納されていることである。 ユーザーは、格納されている情報を要求するときに、サーバから悪意のあるスクリプトを取得し、実行してしまう。 **Reflected XSS Attacks** Reflected attacksとは、リクエストの一部としてサーバに送信された悪意のあるコードが、エラーメッセージ、検索結果、その他いろいろなレスポンスからリフレクションされることである。 ユーザーが、悪意のあるリンクをクリックするか、特別に細工されたフォームを送信すると、挿入されたコードは、ユーザーのブラウザに、攻撃を反映した結果を返却する。 その結果、信頼できるサーバからきた値のため、ブラウザは悪意のあるコードを実行してしまう。 Stored XSS Attacks、Reflected XSS Attacksともに、出力値をエスケープすることで防ぐことができる。 How to use """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" ユーザーの入力を、そのまま出力している場合、XSSの脆弱性にさらされている。 したがって、XSSの脆弱性に対する対抗措置として、HTMLのマークアップ言語で、特定の意味を持つ文字をエスケープする必要がある。 必要に応じて、3種類のエスケープを使い分けること。 エスケープの種類: * Output Escaping * JavaScript Escaping * Event handler Escaping .. _xss_how_to_use_ouput_escaping: Output Escaping ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XSSの脆弱性への対応としては、HTML特殊文字をエスケープすることが基本である。 HTMLにおいてエスケープが必要な特殊文字の例と、エスケープ後の例は、以下の通りである。 .. tabularcolumns:: |p{0.50\linewidth}|p{0.50\linewidth}| .. list-table:: :header-rows: 1 :widths: 50 50 * - | エスケープ前 - | エスケープ後 * - | "``&``" - | ``&`` * - | "``<``" - | ``<`` * - | "``>``" - | ``>`` * - | "\ ``"``\" - | ``"`` * - | "``'``" - | ``'`` XSSを防ぐために、文字列として出力するすべての表示項目に、\ ``f:h()``\ を使用すること。 入力値を、別画面に再出力するアプリケーションを例に、説明する。 出力値をエスケープしない脆弱性のある例 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 本例は、あくまで参考例として載せているだけなので、以下のような実装は、決して行わないこと。 **出力画面の実装** .. code-block:: jsp Job ${customerForm.job} .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | customerFormのフィールドである、jobをエスケープせず出力している。 入力画面のJobフィールドに、 .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 * - 属性名 - 値 * - | warnCode - | ``';alert('XSS Attack!');aaa='message`` 上記例のように、ユーザーの入力を導出元としてコードを出力するなど、JavaScriptの要素を動的に生成する場合、意図せず文字列リテラルが閉じられ、XSSの脆弱性が生じる。 .. figure:: ./images_XSS/javascript_xss_screen_no_escape_result.png :alt: javascript_xss_screen_no_escape_result :width: 35% :align: center **Picture - No Escape Result** **出力結果** .. code-block:: html .. tip:: 業務要件上必要でない限り、JavaScriptの要素をユーザーからの入力値に依存して動的に生成する仕様は、任意のスクリプトが埋め込まれてしまう可能性があるため、別の方式を検討する、または、極力避けるべきである。 .. _xss_how_to_use_js_function_example: 出力値をf:js()関数でエスケープする例 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" XSSを防ぐために、ユーザーの入力値、が設定される値にEL式の関数、\ ``f:js()``\ の使用を推奨する。 使用例を、下記に示す。 .. code-block:: html .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | EL式の\ ``f:js()``\ を使用することにより、エスケープして変数に設定している。 .. figure:: ./images_XSS/javascript_xss_screen_escape_result.png :alt: javascript_xss_screen_escape_result :width: 35% :align: center **Picture - Escape Result** **出力結果** .. code-block:: html .. Warning:: スクリプトタグが含まれる値を、HTMLエスケープせず\ ``f:js()``\でエスケープさせて出力する場合、document.write()を使用すると、 ブラウザにHTMLソースとして解釈させるよう出力するので、XSSの脆弱性が生じる。以下に例を示すが、 **このような実装は決して行わないこと。** **JSP** .. code-block:: html .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 * - 属性名 - 値 * - | warnCode - | ```` **出力結果** .. code-block:: html 出力結果をソースだけ確認するとエスケープできているように見える。 しかし、これは\ ```` \という内容の文字列を変数aaaに格納するコードとなるため、 \ ``document.write(aaa);`` \と実装してしまうと、HTMLのソースとして\ ```` \を出力することになる。 その結果、スクリプトが実行される。 ブラウザに値を出力させたい場合は、JavaScriptを使用せず、HTML特殊文字をエスケープする\ ``f:h()``\を使用することが望ましい。 **JSP** .. code-block:: html ${f:h(warnCode)} **出力結果** .. code-block:: html <script>alert('XSS Attack!');</script> あえて\ ``f:js()``\を使用し、document.write()で出力したい場合は、以下のいずれかのような、追加のXSS対策が必要である。 * HTMLエスケープ用のJavaScript関数を用意し、document.write()の引数をエスケープする。 * \ ``f:h()``\でユーザーの入力値が設定される値をHTMLエスケープした後、\ ``f:js()``\でJavaScriptの文字列リテラル用のエスケープを行う。 .. _xss_how_to_use_event_handler_escaping: Event handler Escaping ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ javascript のイベントハンドラの値をエスケープする場合、\ ``f:h()``\ や、\ ``f:js()``\ を使用するのではなく、\ ``f:hjs()``\ を使用すること。\ ``${f:h(f:js())}``\ と同義である。 理由としては、 \ ````\ のようなイベントハンドラの値に\ ``');alert("XSS Attack");//``\ を指定された場合、別のスクリプトを挿入できてしまうため、文字参照形式にエスケープ後、HTMLエスケープを行う必要がある。 出力値をエスケープしない脆弱性のある例 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" XSS問題が発生する例を、以下に示す。 .. code-block:: jsp .. tabularcolumns:: |p{0.20\linewidth}|p{0.80\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 80 * - 属性名 - 値 * - | warnCode - | ``'); alert('XSS Attack!'); //`` | 上記の値が設定されてしまうことで、意図せず文字列リテラルが閉じられ、XSSの脆弱性が生じる。 マウスオーバ時、XSSのダイアログボックスが表示されてしまう。 .. figure:: ./images_XSS/eventhandler_xss_screen_no_escape_result.png :alt: eventhandler_xss_screen_no_escape_result :width: 50% :align: center **Picture - No Escape Result** **出力結果** .. code-block:: jsp .. _xss_how_to_use_hjs_function_example: 出力値をf:hjs()関数でエスケープする例 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 使用例を、下記に示す。 .. code-block:: jsp // (1) .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - 項番 - 説明 * - | (1) - | EL式の\ ``f:hjs()``\ を使用することにより、エスケープして引数としている。 マウスオーバ時、XSSのダイアログは出力されない。 .. figure:: ./images_XSS/eventhandler_xss_screen_escape_result.png :alt: eventhandler_xss_screen_escape_result :width: 50% :align: center **Picture - Escape Result** **出力結果** .. code-block:: jsp .. raw:: latex \newpage