Documentation

You are viewing the documentation for the 2.2.0 release in the 2.2.x series of releases. The latest stable release series is 2.4.x.

§クロスサイトリクエストフォージェリ対策

クロスサイトリクエストフォージェリ (CSRF) は、攻撃者が被害者のブラウザに被害者のセッションを使ったリクエストを行わせるように仕向ける、セキュリティ上の脆弱性です。セッショントークンはすべてのリクエストにおいて送信されるので、攻撃者が被害者のブラウザに代わってリクエストを強制できる場合、攻撃者は被害者に代わってリクエストを行えるということになります。

CSRF の攻撃ベクトルがどのようなもので、何が攻撃ベクトルでないかについて習熟することをお勧めします。OWASP のこの情報 から始めるとよいでしょう。

端的に言えば、攻撃者は被害者のブラウザに次の種類のリクエストを行うよう強制することができます:

攻撃者は次のことは行えません:

GET リクエストは状態を変えないことを意図しているので、このベストプラクティスに従っているアプリケーションに危険はありません。このため、CSRF 対策が必要なのは、上記で言及されたコンテントタイプを持つ POST リクエストだけです。

§Play の CSRF 対策

Play はリクエストが CSRF リクエストでないことを検証する複数のメソッドを提供しています。その主要なメカニズムは CSRF トークンです。このトークンは、クエリ文字列、または投稿されたすべてのフォームのボディ部分に配置され、同様にユーザーのセッションにも配置されます。そして、Play はこの双方のトークンが存在し、一致することを検証します。

例えば AJAX を通じて行われるような、ブラウザ以外からのリクエストについて簡易に対策できるよう、Play は以下も提供しています:

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

Play はすべてのリクエストに適用できるグローバル CSRF フィルタを提供しています。これがアプリケーションに CSRF 対策を追加するもっとも簡単な方法です。このグローバルフィルタを利用できるようにするには、Play フィルタヘルパーの依存性をプロジェクトの Build.scala に追加します:

val appDependencies = Seq(
  filters
)

ここで Global オブジェクトにフィルタを追加します:

import play.GlobalSettings;
import play.api.mvc.EssentialFilter;
import play.filters.csrf.CSRFFilter;

public class Global extends GlobalSettings {
    @Override
    public <T extends EssentialFilter> Class<T>[] filters() {
        return new Class[]{CSRFFilter.class};
    }
}

§現在のトークンを取得する

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

@import helper._

@form(CSRF(routes.ItemsController.save())) {
    ...
}

これはフォームを以下のようにレンダリングするでしょう:

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

クエリ文字列にトークンを持つことが望しくない場合もあるので、Play は CSRF トークンをフォーム内の hidden フィールドとして追加するヘルパも提供しています:

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

これはフォームを以下のようにレンダリングするでしょう:

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

§CSRF トークンをセッションに追加する

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

§アクションごとに CSRF フィルタリングを適用する

例えば、アプリケーションがいくつかのサイトをまたがったフォーム送信を許可するようにしたい場合など、グローバル CSRF フィルタが適切でない場合もあるかもしれません。Open ID 2.0 のようなセッションを前提としない標準は、サイトをまたがったフォームの送信、または複数サーバ間の RPC コミュニケーションによるフォーム送信を要求します。

このような状況のために、Play はアプリケーションのアクションに合成できる二つのアクションを提供しています。

最初のひとつは、検査を行う play.filters.csrf.RequireCSRFCheck アクションです。これは、セッションで認証される POST フォームの投稿を受け取るすべてのアクションに追加する必要があります:

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

二つ目は、入力されたリクエストに既に存在しなければ CSRF トークンを生成する play.filters.csrf.AddCSRFToken アクションです。これは、フォームをレンダリングするすべてのアクションに追加する必要があります:

@AddCSRFToken
public static Result get() {
    return ok(form.render());
}

Next: JSON を使う