axiosでCSRFトークンをDjangoに返す|CSRF対策

この記事を書いた人

WEB系のプログラミングをメインで扱っており、10年以上に渡りSEO業界の動向を観察して、長く続くサービスとそうでないサービスの違いから、コンテンツSEOについて研究中。自身もWEBアプリやブログを運営しており、過去最高年間売上は3800万円。運営する過程で得られたプログラミングやインフラまわりの知識を使いGoogleが公開しているGoogle検索セントラルを初心者の方にも分かりやすいように解説中。誰が実践しても同じような結果が得られる再現性のある技術に興味がある為、SEO思考プログラミング思考では、SEOとプログラミングに絞って情報を発信中。

abeをフォローする

以下の記事でも解説した通り、DjangoはCSRF対策機能を持っています。

Djangoエラー|CSRF verification failed. Request aborted.|フォームをCSRF攻撃から守る|SSL設定後のエラー

クライアントに、フォームが入ったページを返す際(レスポンスの際)にDjangoはCSRFトークンを発行します。

フォームからDjangoにデータを送り返す際に、このCSRFトークンも一緒に送り返す事で、DjangoはCSRF攻撃されていないと判断します。

axiosでCSRFトークンを返す場合は、cookieを使用する

axiosを使用して非同期通信を行いたい場合、cookieを使うと便利です。

同期通信の場合、CSRFトークンの設定は以下のようになります。

<form action="/example/" method="post">
    {% csrf_token %}
    <input type="text" name="search">
    <input type="submit" value="送信する">
</form>
<!-- {% csrf_token %}の部分はDjangoでレンダリングされるとCSRFトークン入りのinput要素になります -->

同期通信の場合「送信する」のボタンをクリックすると、CSRFトークンが、HTTPリクエストヘッダに格納され、Djangoに送られます。

一方、axiosを使用した非同期通信の場合、フォームに設置したCSRFトークンを使用するよりも、cookieに保存されているCSRFトークンを使用すると便利です。


<!doctype html>
<html lang="ja">
   <head>
      <!-- ヘッダ情報 -->
   </head>
   <body>
      <!-- ボディ情報 -->
      {% csrf_token %}
   </body>

HTMLファイルの任意の場所に、{% csrf_token %}を記述します。

この記述は、Djangoがレンダリングすると、

<input type=”hidden” name=”csrfmiddlewaretoken” value=”example”>

となり、クライアントにCSRFトークンを渡しています。

更に、この記述をする事で、クライアントにページを送る際にHTTPレスポンスのcookieにCSRFトークンを格納しています。

非同期通信の場合、このcookieに保存されたCSRFトークンをDjangoに送り返します。

//Vue.jsで設定する場合
methods: {
   returnCsrfToken(){
      axios.defaults.xsrfCookieName = 'csrftoken'
      axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'
      axios({
         method: 'POST',
         url: example.com
         data: {example:exampleData}
      })
      .then(response => {
         console.log('トークンを送った')
      })
   }
},
//以下2行を追記する事でクッキーに保存されているCSRFトークンがHTTPリクエストヘッダに格納される
//axios.defaults.xsrfCookieName = 'csrftoken'
//axios.defaults.xsrfHeaderName = 'X-CSRFTOKEN'

同期、非同期問わず、{% csrf_token %}は必要

以上のように、HTMLファイルに、{% csrf_token %}の記述をする事で、Djangoは、HTTPレスポンスヘッダと、HTTPレスポンスボディの両方にCSRFトークンを格納します。

あとは、Djangoから送られてきたCSRFトークンを、送り返せば、CSRF対策ができます。

コメント

タイトルとURLをコピーしました