ドキュメント

§クロスサイトリクエストフォージェリに対する保護

クロスサイトリクエストフォージェリ(CSRF)は、攻撃者が被害者のブラウザをだまして、被害者のセッションを使用してリクエストを送信させるセキュリティ攻撃です。セッション トークンはすべてのリクエストで送信されるため、攻撃者が被害者のブラウザを強制的に自分の代わりにリクエストを送信させることができる場合、攻撃者はユーザーの代わりにリクエストを送信できます。

CSRF、攻撃ベクトルの種類、および攻撃ベクトルではないものをよく理解しておくことをお勧めします。まずは、OWASPからのこの情報から始めることをお勧めします。

どのリクエストが安全で、どのリクエストがCSRFリクエストに対して脆弱であるかについては、簡単な答えはありません。その理由は、プラグインや仕様の将来の拡張から何が許可されるかについての明確な仕様がないためです。歴史的に、ブラウザのプラグインと拡張機能は、フレームワークが以前は信頼できると考えていたルールを緩和し、多くのアプリケーションにCSRFの脆弱性を導入しており、それらを修正する責任はフレームワークにありました。このため、Playはデフォルトで控えめなアプローチを取りますが、チェックを実行するタイミングを正確に構成できます。デフォルトでは、次のすべてが当てはまる場合、PlayはCSRFチェックを要求します。

注: CookieまたはHTTP認証を使用する以外のブラウザベースの認証(NTLMやクライアント証明書ベースの認証など)を使用する場合は、play.filters.csrf.header.protectHeaders = nullを設定して、すべてのリクエストを保護するか、認証で使用されるヘッダーをprotectHeadersに含める必要があります

§PlayのCSRF保護

Playは、リクエストがCSRFリクエストではないことを検証するための複数の方法をサポートしています。主なメカニズムはCSRFトークンです。このトークンは、送信されたすべてのフォームのクエリ文字列または本文に配置され、ユーザーセッションにも配置されます。Playは、両方のトークンが存在し、一致することを確認します。

ブラウザ以外のリクエストに対する簡単な保護を許可するために、PlayはデフォルトでCookieまたはAuthorizationヘッダーを含むリクエストをチェックします。play.filters.csrf.header.protectHeadersを構成して、CSRFチェックを実行するために存在する必要のあるヘッダーを定義できます。AJAXでリクエストを作成する場合は、CSRFトークンをHTMLページに配置し、Csrf-Tokenヘッダーを使用してリクエストに追加できます。

または、play.filters.csrf.header.bypassHeadersを構成して、一般的なヘッダーと一致させることもできます。一般的な構成は次のようになります。

この構成は次のようになります。

play.filters.csrf.header.bypassHeaders {
  X-Requested-With = "*"
  Csrf-Token = "nocheck"
}

歴史的にブラウザのプラグインがこのタイプのCSRF防御を弱体化させてきたため、この構成オプションを使用する場合は注意が必要です。

§CORSリクエストの信頼

デフォルトでは、CSRFフィルターの前にCORSフィルターがある場合、CSRFフィルターは信頼できるオリジンからのCORSリクエストを許可します。このチェックを無効にするには、構成オプションplay.filters.csrf.bypassCorsTrustedOrigins = falseを設定します。

§グローバルCSRFフィルターの適用

注: Play 2.6.x以降、CSRFフィルターは、プロジェクトに自動的に適用されるPlayのデフォルトフィルターのリストに含まれています。詳細については、フィルターのページを参照してください。

Playは、すべてのリクエストに適用できるグローバルCSRFフィルターを提供します。これは、アプリケーションにCSRF保護を追加する最も簡単な方法です。フィルターを手動で追加するには、application.confに追加します。

play.filters.enabled += "play.filters.csrf.CSRFFilter"

routesファイルで特定のルートのCSRFフィルターを無効にすることもできます。これを行うには、ルートの前にnocsrf修飾子タグを追加します。

+ nocsrf
POST  /api/new              controllers.Api.newThing()

§現在のトークンの取得

現在のCSRFトークンは、CSRF.getTokenメソッドを使用してアクセスできます。これは、RequestHeaderを受け取ります。

Optional<CSRF.Token> token = CSRF.getToken(request);

:CSRFフィルターがインストールされている場合、Playは使用されているCookieがHttpOnly(つまり、JavaScriptからアクセスできない)である限り、トークンの生成を回避しようとします。厳密なボディを持つレスポンスを送信する場合、PlayはCSRF.getTokenがすでに呼び出されていない限り、レスポンスへのトークンの追加をスキップします。これにより、CSRFトークンを必要としないレスポンスのパフォーマンスが大幅に向上します。CookieがHttpOnlyになるように構成されていない場合、PlayはJavaScriptからアクセスしたいと想定し、トークンを生成します。

フォームにCSRFトークンを追加するのを支援するために、Playはいくつかのテンプレートヘルパーを提供します。最初のものは、アクションURLのクエリ文字列に追加します。

@import helper._

@form(CSRF(scalaguide.forms.csrf.routes.ItemsController.save())) {
    ...
}

これにより、次のようなフォームがレンダリングされる可能性があります。

<form method="POST" action="/items?csrfToken=1234567890abcdef">
   ...
</form>

クエリ文字列にトークンを含めるのが望ましくない場合、Playはフォームに非表示フィールドとしてCSRFトークンを追加するためのヘルパーも提供します。

@form(scalaguide.forms.csrf.routes.ItemsController.save()) {
    @CSRF.formField
    ...
}

これにより、次のようなフォームがレンダリングされる可能性があります。

<form method="POST" action="/items">
   <input type="hidden" name="csrfToken" value="1234567890abcdef"/>
   ...
</form>

§セッションへのCSRFトークンの追加

フォームでレンダリングされ、クライアントに送り返されるCSRFトークンが利用可能であることを保証するために、グローバルフィルターは、受信リクエストにトークンがまだ利用可能でない場合、HTMLを受け入れるすべてのGETリクエストに対して新しいトークンを生成します。

§アクションごとのCSRFフィルタリングの適用

グローバルCSRFフィルタリングが適切でない場合があります。たとえば、アプリケーションがいくつかのクロスオリジンフォームポストを許可したい場合などです。OpenID 2.0などのセッションベースではない一部の標準では、クロスサイトフォームの投稿を使用するか、サーバー間RPC通信でフォーム送信を使用する必要があります。

このような場合、Playはアプリケーションのアクションと組み合わせて構成できる2つのアクションを提供します。

最初のアクションは、CSRFチェックを実行するplay.filters.csrf.RequireCSRFCheckアクションです。セッション認証されたPOSTフォーム送信を受け入れるすべてのアクションに追加する必要があります。

@RequireCSRFCheck
public Result save() {
  // Handle body
  return ok();
}

2番目のアクションは、受信リクエストにまだ存在しない場合にCSRFトークンを生成するplay.filters.csrf.AddCSRFTokenアクションです。フォームをレンダリングするすべてのアクションに追加する必要があります。

@AddCSRFToken
public Result get(Http.Request request) {
  return ok(CSRF.getToken(request).map(CSRF.Token::value).orElse("no token"));
}

§CSRF構成オプション

CSRF構成オプションの完全な範囲は、フィルターのreference.confにあります。いくつかの例を以下に示します。

§CSRFのテスト

機能テストで、CSRFトークンを使用してTwirlテンプレートをレンダリングしている場合は、CSRFトークンを使用できる必要があります。これは、play.mvc.Http.RequestBuilderインスタンスでplay.api.test.CSRFTokenHelper.addCSRFTokenを呼び出すことで実行できます。

Http.RequestBuilder request = new Http.RequestBuilder().method(POST).uri("/xx/Kiwi");

request = CSRFTokenHelper.addCSRFToken(request);

次へ: フォームテンプレートヘルパーの使用


このドキュメントにエラーを見つけましたか?このページのソースコードはこちらにあります。 ドキュメントガイドラインをお読みになった後、プルリクエストをお気軽にお送りください。質問や共有したいアドバイスはありますか? コミュニティフォーラムでコミュニティとの会話を始めましょう。