search
LoginSignup
22

More than 5 years have passed since last update.

posted at

updated at

DjangoのCSRF周りの設定

Django 1.11.6版です

前の記事でCSRF周りの内容がスッポリ抜けていたので、追加メモです。

送信フォームでの設定

基本中の基本ですね。テンプレートの中に{% csrf_token %}を入れておけば終わりです。

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

実際のHTMLでは{% csrf_token %}が

<input type='hidden' name='csrfmiddlewaretoken' value='値' />

と展開されます。

Ajaxでの設定

TypeScriptで書いていますが、ほとんどJavaScriptそのままで動くかと思います。ただしfindのところでUnderscore使ってますので、使わない場合はfindの代わりの実装が必要です。

Djangoからページを取得した時のHTTPレスポンスのcookieにCSRFの情報が格納されています。

JavaScriptからはdocument.cookieよりcsrftokenというパラメータ名で取得できるので、POSTする時にcsrftokenの内容をX-CSRFTokenという名前でHTTPのヘッダに設定して送り返します。

let xhr = new XMLHttpRequest();
xhr.open("POST", "api");

// 送るデータの設定
let params:any = {
};

// for Django
// ------------------------------------------------
let CSRF_KEY_NAME="csrftoken=";
let csrf = _.find(document.cookie.split(";"), (cookie)=>{
    return cookie.trim().substr(0, CSRF_KEY_NAME.length) == CSRF_KEY_NAME;
})
if(csrf) xhr.setRequestHeader("X-CSRFToken", csrf.trim().substr(CSRF_KEY_NAME.length));
// ------------------------------------------------

xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(JSON.stringify(params));

※document.cookieは;区切り。;の後にスペースもあるのでtrimして使ってます

なお、ここではあまり関係がないのですがついでなので……
Pythonでfind

next((val for val in リスト if 条件), デフォルト値)

で、最初の条件にマッチしたリストの中身を返し、リストに無ければデフォルト値を返します。

タプルの内包表記はPython3だと遅延評価になるので(generatorが返る)速度も優秀です。

テストでCSRFを無効にする

テストの時はCSRF認証を止めてPOSTすることができます。

from django.test.client import Client
client = Client(enforce_csrf_checks=False)
公式ドキュメント読んだらデフォルトがFalseだとか(´・ω・`)ジツハイラナイ

# パスワード無し時の動作テスト
result = client.post('/account/auth', {"user":"unknown_user"})
self.assertEqual(result.status_code, 403)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
22