クロスサイトリクエストフォージェリ (CSRF) 対策

revision-up-to:11321 (1.1) unfinished

CsrfMiddleware クラスは、簡単に使える クロスサイトリクエストフォージェリ 対策を提供しています。このタイプの攻撃は、悪意あるウェブサイトが、あなたの ウェブサイトに対して、ログイン済みユーザの権限で何らかの操作を行うように作 られたリンクやフォームボタンを自分のサイトに設置しておき、ログイン済みのユー ザがユーザが自分のブラウザを使ってボタンやリンクをクリックするように仕向け ることで起こります。

CSRF 攻撃に対する第一の防御は、 GET リクエストから副作用を取り除くというも のです。 POST リクエストに対する防御は、このミドルウェアをインストール済み ミドルウェアリストに追加して実現できます。

使い方

'django.contrib.csrf.middleware.CsrfMiddleware' ミドルウェアを MIDDLEWARE_CLASSES に追加してください。このミドルウェアは SessionMiddleware よりも後にレスポンスを処理せねばならないので、リスト中の SessionMiddleware よりも前に配置します。また、圧縮のような操作が入る前のレ スポンスを処理せねばならないので、 GZipMiddleware よりも後に配置します。

The CsrfMiddleware class is actually composed of two middleware: CsrfViewMiddleware which performs the checks on incoming requests, and CsrfResponseMiddleware which performs post-processing of the result. This allows the individual components to be used and/or replaced instead of using CsrfMiddleware.

Django 1.1 で変更されました: (previous versions of Django did not provide these two components of CsrfMiddleware as described above)

Exceptions

Django 1.1 で新たに登場しました: Please, see the release notes

To manually exclude a view function from being handled by the CsrfMiddleware, you can use the csrf_exempt decorator, found in the django.contrib.csrf.middleware module. For example:

from django.contrib.csrf.middleware import csrf_exempt

def my_view(request):
    return HttpResponse('Hello world')
my_view = csrf_exempt(my_view)

Like the middleware itself, the csrf_exempt decorator is composed of two parts: a csrf_view_exempt decorator and a csrf_response_exempt decorator, found in the same module. These disable the view protection mechanism (CsrfViewMiddleware) and the response post-processing (CsrfResponseMiddleware) respectively. They can be used individually if required.

You don't have to worry about doing this for most AJAX views. Any request sent with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the next section.)

仕組み

CsrfMiddleware は以下のような処理を行います:

  1. CsrfMiddleware は、サーバから出てゆくレスポンス内の 'POST' フォーム全て に対して 'csrfmiddlewaretoken' という名前の隠しフィールドを追加します。 このフィールドの値はセッション ID とシークレット文字列の和をハッシュした ものになります。セッション ID が設定されていない場合、レスポンスに対する 変更は行いません。このため、セッションをともなわないリクエストに対しては 非常にわずかなパフォーマンスペナルティしかもたらしません。 (実際には CsrfResponseMiddleware がこの処理を担当します。)
  2. セッションクッキーのセットされた全ての POST リクエストに対し、 'csrfmiddlewaretoken' がセットされていて、かつ正しい値になっているか調べ ます。正しい値でなければ、 403 エラーを返します。 (実際には CsrfViewMiddleware がこの処理を担当します。)

これらの処理により、あなたのウェブサイト由来のフォームだけが POST を送り返 せるようになります。

このミドルウェアは、 HTTP POST リクエスト (と POST フォーム) だけを対象にし ています。 GET リクエストには危険な副作用を持たないはず (RFC 2616: HTTP 1.1 の 9.1.1 節、「安全なメソッド」 を参照) なので、 GET リクエストを使った CSRF 攻撃は威力を持たないのです。

セッションクッキーを伴わない POST リクエストは保護されませんが、セッション クッキーを伴わないようなフォームに対しては、攻撃側のウェブサイトはリクエス トをどのようにでも作れてしまうので、そもそも保護する意味はありません。

CsrfMiddleware はレスポンスを変更する前に Content-Type をチェックし、 'text/html' または 'application/xml+xhtml' のページだけを変更します。

The middleware tries to be smart about requests that come in via AJAX. Many JavaScript toolkits send an "X-Requested-With: XMLHttpRequest" HTTP header; these requests are detected and automatically not handled by this middleware. We can do this safely because, in the context of a browser, the header can only be added by using XMLHttpRequest, and browsers already implement a same-domain policy for XMLHttpRequest. (Note that this is not secure if you don't trust content within the same domain or subdomains.)

制限

CsrfMiddleware を動作させるには、 Django のセッションフレームワークが必要で す。手動でクッキーを設定するカスタムの認証システムなどを使っている場合には うまく動作しません。

アプリケーションで HTML ページやフォームを普通とは違うやり方で生成している 場合 (JavaScript の document.write 文などで HTML フラグメントを送信するよう な場合)、フォームの隠しフィールドを追加するフィルタを回避してしまうかもしれ ません。そのような場合、フォームの提出は常に失敗してしまいます。ただし、 CSRF 対策トークンを取得し、提出されるフォームに必ずトークンが入るようにすれ ば、このミドルウェアを使う余地はあるでしょう。