name.Caution本バージョンの内容は既に古くなっています。最新のガイドラインはこちらからご参照ください。forgeries(以下、CSRFと略す)とは、Webサイトにスクリプトや自動転送(HTTPリダイレクト)を実装することにより、ユーザが、ログイン済みの別のWebサイト上で、意図しない何らかの操作を行わせる攻撃手法のことである。サーバ側でCSRFを防ぐには、以下の方法が知られている。秘密情報(トークン)の埋め込みパスワードの再入力ReferのチェックOWASPでは、トークンパターンを使用する方法が推奨されている。効果的なアプローチなどを検証、提唱する、国際的な非営利団体である。Securityが提供している。セッション毎に1つの固定トークンを用い、すべてのリクエストについて、同じ値を使用している。Status:403[Forbidden])とする。kindTipCSRFトークンチェックは、別サイトからの不正な更新リクエストをチェックし、エラーとするものである。ユーザに順序性(一連の業務フロー)を守らせ、チェックするためには、トランザクショントークンチェックについてを参照されたい。Securityの3.2.0.RELEASE版は未リリースであるため)。SecurityのCSRF対策機能に関する以下のクラスが同梱されている。Securityのバージョンアップし、上記のクラスは、terasoluna-gfw-security-webプロジェクトからは取り除かれる予定である。SecurityのCSRF機能を使用するための設定を説明する。useで設定したweb.xmlを前提とする。追加で設定が必要な箇所を、ハイライトしている。CSRFのFilter定義を行う。(2)<sec:session-management>要素の、session-authentication-strategy-ref属性で、org.springframework.security.web.authentication.session.SessionAuthenticationStrategyを参照する。(3)org.springframework.security.web.csrf.CsrfFilterのbean定義を行う。(4)コンストラクタの第1引数で、トークンの作成、保持を行うorg.springframework.security.web.csrf.CsrfTokenRepositoryを参照する。(6)AccessDeniedHandlerImplのerrorPageプロパティに、リクエストに含まれるCSRFトークンが、一致しない場合の遷移先パスを設定する。設定を省略した場合、リクエストに含まれるCSRFトークンが一致しない場合、ステータスコード403でクライアントに返却する。(7)CsrfTokenRepositoryの実装としてHTTPセッションにCSRFトークンを保存する、org.springframework.security.web.csrf.HttpSessionCsrfTokenRepositoryクラスを定義する。(8)SessionAuthenticationStrategyの実装として、複数のSessionAuthenticationStrategyを使用できるorg.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy(9)CompositeSessionAuthenticationStrategyに、org.springframework.security.web.csrf.CsrfAuthenticationStrategyを追加する。(10)CompositeSessionAuthenticationStrategyコンストラクタの第1引数で、CsrfTokenRepositoryを参照する。NoteAccessDeniedHandlerImplのerrorPageプロパティを省略した場合の、エラーハンドリングについてweb.xmlに、以下の設定を行うことで、任意のページに遷移させることができる。説明(1)error-code要素に、ステータスコード403を設定する。(2)location要素に、遷移先のパスを設定する。実装した、独自のAccessDeniedHandlerを作成する必要がある。Securityのレファレンスドキュメントを参照されたい。前述した設定を省略することができる。Securityのレファレンスドキュメントを参照されたい。spring-mvc.xmlの設定¶CSRFトークン用のRequestDataValueProcessor実装クラスを利用し、Springのタグライブラリの<form:form>タグを使うことで、自動的にCSRFトークンを、hiddenに埋め込むことができる。説明(1)org.terasoluna.gfw.web.mvc.support.RequestDataValueProcessorを複数定義可能な、org.terasoluna.gfw.web.mvc.support.CompositeRequestDataValueProcessorをbean定義する。(2)コンストラクタの第1引数に、org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessorのbean定義を設定する。factory-methodに、createメソッドを指定する。NoteCSRFトークンの生成、チェックは、CsrfFilterが行うため、Controllerでは特に、CSRF対策は意識しなくてよい。type="hidden">タグを作成し、明示的にCSRFトークンを埋め込むのどちらかを行う必要がある。type="hidden">タグが、自動的に追加される。JSPで、CSRFトークンを意識する必要はない。/></form:form>以下のようなHTMLが、出力される。type="hidden">タグが追加され、CSRFトークンが埋め込まれているとわかる。CSRFトークンはログインのタイミングで生成される。<form:form>でGETを指定してフォームを送信した場合、ブラウザのアドレスバーのURLに、CSRFトークンが含まれ、ブックマークバーやアクセスログに残る。</spring:nestedPath></form>`と記述すればよい。token.と説明されており、必須ではないが対応することが推奨される。IDは漏洩することはない。ログインの度にCSRFトークンは変更される。method="GET">を使用してもCSRFトークンはURLに現れない)。type="hidden">タグを追加する必要がある。説明(1)_csrf.parameterNameでリクエストパラメータ名を、_csrf.tokenで、CSRFトークンを設定する。以下のようなHTMLが、出力される。サーバー上に保存されているトークン値と、送信されたトークン値が異なる場合は、AccessDeniedHandlerによりアクセス拒否処理が行われる。デフォルトでは403エラーとなり、AccessDeniedHandlerImplのerrorPageプロパティで指定したエラーページに遷移する。詳細は、spring-security.xmlの設定を参照されたい。前述のようにリクエストパラメータからCSRFトークンを取得するだけでなく、HTTPリクエストヘッダーからもCSRFトークンを取得する。Ajaxを利用する場合はHTTPヘッダーに、CSRFトークンを設定することを推奨する。JSON形式でリクエストを送る場合にも対応できるためである。NoteHTTPヘッダ、リクエストパラメータの両方からCSRFトークンが送信する場合は、HTTPヘッダの値が優先される。Ajaxで使用した例を用いて、説明を行う。追加で設定が必要な箇所を、ハイライトしている。説明(1)<meta>タグに、${f:h(_csrf.token)}で取得したCSRFトークンを設定する。(2)<meta>タグに、${f:h(_csrf.headerName)}で取得したヘッダ名を設定する。(3)<meta>タグに、設定したCSRFトークンを取得する。(4)<meta>タグに、設定したCSRFヘッダ名を取得する。(5)リクエストヘッダーに、<meta>タグで設定したヘッダ名(デフォルト:X-CSRF-TOKEN)、CSRFトークンの値を設定する。(6)この書き方はXSSの可能性があるので、実際にJavaScriptコードを書くときは気を付けること。今回の例ではdata.addResult、data.subtractResult、data.multipyResult、data.divideResultの全てが数値型であるため、問題ない。JSONでリクエストを送信する場合も、同様にHTTPヘッダを設定すればよい。TodoAjax対応する例がなくなっているため、例を直す。一般的に、ファイルアップロードなどマルチパートリクエストを送る場合、formから送信される値をFilterでは取得できない。そのため、これまでの説明だけでは、マルチパートリクエスト時にCsrfFileterがCSRFトークンを取得できず、不正なリクエストと見なされてしまう。そのため、以下のどちらかの方法によって、対策する必要がある。通常、マルチパートリクエストの場合、formから送信された値はFilter内で取得できない。org.springframework.web.multipart.support.MultipartFilterを使用することで、マルチパートリクエストでも、Filter内で、formから送信された値を取得することができる。MultipartFilterを使用するには、以下のように設定すればよい。(2)springSecurityFilterChainより前に、MultipartFilterを定義すること。type="hidden">タグが自動的に追加されるため、JSPの実装で、CSRFトークンを意識する必要はない。タグを使用する場合CSRFトークンを明示的に埋め込む方法でCSRFトークンを設定すること。説明(1)<form:form>タグのaction属性に、以下のクエリを付与する必要がある。?${f:h(_csrf.parameterName)}=${f:h(_csrf.token)}<form>タグを使用する場合も、同様の設定が必要である。ファイルアップロードの詳細については、FileUploadを参照されたい。Warningこの方法も前述したCSRFがURLに現れるという問題がある。認証されていないユーザーのアップロード(一時ファイル作成)を許容してしまう。これを防ぐ必要がある場合に、クエリパラメータでCSRFトークンを送る必要がある。