csrf_tokenとは?

- django

csrf_tokenとは

Djangoのformの記事を見ていると次のような記述をよく見ます。

<form method="post">{% csrf_token %}

前半部分はいわゆるフォームタグですが、その後ろのやつは何?となったのでまとめようと思います。

csrfとは

CyberSecurityTIMES様とTrend Micro様を参考にまとめます。 csrf(クロスサイト・リクエスト・フォージェリ)は上のサイトでは次のように説明されています。

クロスサイトリクエストフォージェリ(CSRF)とは、Webアプリケーションに存在する脆弱性、もしくはその脆弱性を利用した攻撃方法のことです。掲示板や問い合わせフォームなどを処理するWebアプリケーションが、本来拒否すべき他サイトからのリクエストを受信し処理してしまいます。

攻撃の手法・特徴

  • 攻撃者は攻撃用Webページを準備し、ユーザがアクセスするよう誘導します
  • ユーザが攻撃用Webページにアクセスすると、攻撃用Webページ内にあらかじめ用意されていた不正なリクエストが攻撃対象サーバに送られます
  • 攻撃対象サーバ上のWebアプリケーションは不正なリクエストを処理し、ユーザが意図していない処理が行われてしまいます

また、より具体的な被害も次のように紹介されています。

影響と被害

攻撃者は自身が直接攻撃対象サーバへアクセスすることなく、攻撃対象のWebアプリケーションに任意の処理を行わせることができます。CSRFを利用して行われる主な攻撃としては、以下があります:

  • いたずら的書き込み、不正サイトへの誘導、犯罪予告といった掲示板やアンケートフォームへの不正な書き込み
  • 不正な書き込みを大量に行うことによるDoS攻撃

自身が被害者になるだけでなく、加害者になってしまう可能性があるのも怖いですね...

{% csrf_token %}について

Djangoの学習ができるチュートリアルサイトDjangoBrothers様の記事がわかりやすかったのでこちらを参考に紹介します。

Djangoにはデフォルトでcsrfの検証を行ってくれるアプリが存在し、それが'django.middleware.csrf.CsrfViewMiddleware'です。 使い方は非常にシンプルで<form method="post">{% csrf_token %}のようにフォームタグの後ろにDjangoテンプレートタグのcsrfタグをくっつけてあげることで使用できます。 これにより次のようなフォームタグが生成されます。

<input type="hidden" name="csrfmiddlewaretoken" value="JjAP5uW656Xn9WMLZ3chqT1haPekrHDQil0KOgNpR0WVojLhN4T4Q9N3B2te6CqW">

typeがhiddenなので画面には表示されません。 valueに格納されているのがサーバーで発行されたトークンであり、これがフォームが送信されるタイミングで一緒に送信され、サーバー側はこのトークンが正しいものか検証することで正常なリクエストかを判断して処理を実行します。

注意点

注意点は以下の二つです。

  • {% csrf_token %}の付け忘れ
  • 外部リンクへのpostの際に付けてしまうこと

一つ目から説明します。

前述した通り、postは{% csrf_token %}が正しいかによってリクエストの正常さを評価します。したがって、これをつけ忘れてしまった場合、正常なリクエストと認識されず、403エラーが返ってきてしまいます。

なお、こちらを無効化する方法もDjangoの学習ができるチュートリアルサイトDjangoBrothersに記載がありますので気になる方はご確認ください。

二つ目を説明します。

外部へのリンクにpostする際にこちらを付けてしまうと外部に対してtokenが渡されてしまうため、セキュリティ上の問題になります。したがって、外部へpostする際は外しましょう。