forgeries(以下、CSRFと略す)対策の機能について説明する。ユーザーが、ログイン済みの別のWebサイト上で、意図しない何らかの操作を行わせる攻撃手法のことである。サーバ側でCSRFを防ぐには、以下の方法が知られている。秘密情報(トークン)の埋め込みパスワードの再入力RefererのチェックCSRF対策機能は、攻撃者が用意したWebページから送られてくる偽造リクエストを不正なリクエストとして扱うための機能である。CSRF対策が行われていないWebアプリケーションを利用すると、以下のような方法で攻撃を受ける可能性がある。利用者は、CSRF対策が行われていないWebアプリケーションにログインする。利用者は、攻撃者からの巧みな誘導によって、攻撃者が用意したWebページを開いてしまう。攻撃者が用意したWebページは、フォームの自動送信などのテクニックを使用して、偽造したリクエストをCSRF対策が行われていないWebアプリケーションに対して送信する。CSRF対策が行われていないWebアプリケーションは、攻撃者が偽造したリクエストを正規のリクエストとして処理してしまう。TipOWASP[1]では、トークンパターンを使用する方法が推奨されている。効果的なアプローチなどを検証、提唱する、国際的な非営利団体である。https://www.owasp.org/index.php/Main_PageNoteログイン時におけるCSRF対策CSRF対策はログイン中のリクエストだけではなく、ログイン処理でも行う必要がある。ログイン処理に対してCSRF対策を怠った場合、攻撃者が用意したアカウントを使って知らぬ間にログインさせられ、ログイン中に行った操作履歴などを盗まれる可能性がある。Filterの設定を留意されたい。Securityは、セッション単位にランダムに生成される固定トークン値(CSRFトークン)を払い出し、払い出されたCSRFトークンをリクエストパラメータ(HTMLフォームのhidden項目)として送信する。これにより正規のWebページからのリクエストなのか、攻撃者が用意したWebページからのリクエストなのかを判断する仕組みを採用している。説明(1)クライアントは、HTTPのGETメソッドを使用してアプリケーションサーバにアクセスする。Securityは、CSRFトークンを生成しHTTPセッションに格納する。生成したCSRFトークンは、HTMLフォームのhiddenタグを使ってクライアントと連携する。(3)クライアントは、HTMLフォーム内のボタンを押下してアプリケーションサーバーにリクエストを送信する。HTMLフォーム内のhidden項目にCSRFトークンが埋め込まれているため、CSRFトークン値はリクエストパラメータとして送信される。Securityは、HTTPのPOSTメソッドを使ってアクセスされた際は、リクエストパラメータに指定されたCSRFトークン値とHTTPセッション内に保持しているCSRFトークン値が同じ値であることをチェックする。トークン値が一致しない場合は、不正なリクエスト(攻撃者からのリクエスト)としてエラーを発生させる。(5)クライアントは、HTTPのGETメソッドを使用してアプリケーションサーバにアクセスする。Securityは、GETメソッドを使ってアクセスされた際は、CSRFトークン値のチェックは行わない。Securityは、リクエストヘッダにCSRFトークン値を設定することができるため、Ajax向けのリクエストなどに対してCSRF対策を行うことが可能である。Securityのデフォルト実装では、以下のHTTPメソッドを使用したリクエストに対して、CSRFトークンチェックを行う。メソッドがチェック対象外となっている理由は、これらのメソッドがアプリケーションの状態を変更するようなリクエストを実行するためのメソッドではないためである。CSRF対策機能の適用¶CSRFトークン用のRequestDataValueProcessor実装クラスを利用し、Springのタグライブラリの<form:form>タグを使うことで、自動的にCSRFトークンを、hiddenに埋め込むことができる。説明(1)共通ライブラリから提供されている、org.springframework.web.servlet.support.RequestDataValueProcessorを複数定義可能なorg.terasoluna.gfw.web.mvc.support.CompositeRequestDataValueProcessorをbean定義する。(2)コンストラクタの第1引数に、org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessorのbean定義を設定する。4.0からは、上記設定により、デフォルトでCSRF対策機能が有効となる。このため、CSRF対策機能を適用したくない場合は、明示的に無効化する必要がある。CSRF対策機能を使用しない場合は、以下のようなbean定義を行う。Securityは、CSRFトークン値をクライアントとサーバー間で連携する方法として、以下の2種類の方法を提供している。MVCと連携するためのコンポーネントをいくつか提供している。ここでは、CSRF対策機能と連携するためのコンポーネントの使い方を説明する。hidden項目の自動出力¶HTMLフォームを作成する際は、以下のようなJSPの実装を行う。MVCから提供されている<form:form>要素を使用する。MVCから提供されている<form:form>要素を使うと、以下のようなHTMLフォームが作成される。type="hidden">タグが出力される。type="hidden">タグは出力されない。token.に対応している事を意味しており、セキュアなWebアプリケーション構築の手助けとなる。せずに、HTMLフォームを使用してCSRFトークン値を連携することも可能である。HTMLフォームを使ってリクエストを送信する場合は、HTMLフォームのhidden項目としてCSRFトークン値を出力し、リクエストパラメータとして連携する。説明(1)HTMLの<form>要素の中に<sec:csrfInput>要素を指定する。Securityから提供されている<sec:csrfInput>要素を指定すると、以下のようなhidden項目が出力される。HTMLフォーム内にhidden項目を出力することで、CSRFトークン値がリクエストパラメータとして連携される。デフォルトでは、CSRFトークン値を連携するためのリクエストパラメータ名は_csrfになる。--></form>WarningGETメソッド使用時の注意点HTTPメソッドとしてGETを使用する場合、<sec:csrfInput>要素を指定しないこと。<sec:csrfInput>要素を指定してしまうと、URLにCSRFトークン値が含まれてしまうため、CSRFトークン値が盗まれるリスクが高くなる。Ajax使用時の連携¶Ajaxを使ってリクエストを送信する場合は、HTMLのmetaタグとしてCSRFトークンの情報を出力し、metaタグから取得したトークン値をAjax通信時のリクエストヘッダに設定して連携する。Securityから提供されているJSPタグライブラリを使用して、HTMLのmetaタグにCSRFトークンの情報を出力する。説明(1)HTMLの<head>要素内に<sec:csrfMetaTags>要素を指定する。<sec:csrfMetaTags>要素を指定すると、以下のようなmetaタグが出力される。デフォルトでは、CSRFトークン値を連携するためのリクエストヘッダ名はX-CSRF-TOKENとなる。CSRFトークン値を設定する。説明(1)CSRFトークン値を連携するためのリクエストヘッダ名を取得する。(2)CSRFトークン値を取得する。(3)リクエストヘッダにCSRFトークン値を設定する。AccessDeniedExceptionをハンドリングして、その例外に対応した遷移先を指定する。CSRFのトークンチェックエラー時に発生する例外は以下の通りである。説明InvalidCsrfTokenExceptionクライアントから送られたトークン値と、サーバー側で保持しているトークン値が一致しない場合に使用する例外クラス(主に不正なリクエスト)。MissingCsrfTokenExceptionサーバー側にトークン値が保存されていない場合に使用する例外クラス(主にセッション切れ)。AccessDeniedHandlerインタフェースの実装クラスを割り当てることで、例外毎の遷移先を設定することが可能である。CSRFトークンチェックエラー時に専用のエラー画面(JSP)に遷移させたい場合は、以下のようなBean定義を行う。説明(1)<sec:access-denied-handler>タグのref属性に、Exception毎の制御を行うためのAccessDeniedHandlerのBean名を指定する。属性に遷移先を指定すればよい。<sec:access-denied-handler>でハンドリングしない場合は、認可エラー時の遷移先を参照されたい。)をMap形式で定義する。AccessDeniedExceptionのサブクラスを指定する。errorPageを指定し、valueに表示するviewを指定する。(5)(4)のExceptionと異なるExceptionを制御したい場合に定義する。InvalidCsrfTokenException、MissingCsrfTokenExceptionそれぞれに異なる遷移先を設定している。)と遷移先を指定する。Note無効なセッションを使ったリクエストの検知セッション管理機能の「無効なセッションを使ったリクエストの検知」処理を有効にしている場合は、MissingCsrfTokenExceptionに対して「無効なセッションを使ったリクエストの検知」処理と連動するAccessDeniedHandlerインタフェースの実装クラスが適用される。そのため、MissingCsrfTokenExceptionが発生すると、「無効なセッションを使ったリクエストの検知」処理を有効化する際に指定したパス(invalid-session-url)にリダイレクトする。Noteステータスコード403以外を返却したい場合リクエストに含まれるCSRFトークンが一致しない場合に、ステータスコード403以外を返却したい場合は、org.springframework.security.web.access.AccessDeniedHandlerインタフェースを実装した、独自のAccessDeniedHandlerを作成する必要がある。