読者です 読者をやめる 読者になる 読者になる

へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)!

DjangoのCSRF token missing or incorrect.についての解決

追記

csrf_tokenは、単にPOSTするときに投げるランダムに生成された文字列だよ

クライアントXは、あるページにHTTPRequest(GET)でアクセスする。
→サーバ側で、Djangoがランダムな文字列を生成
→そのランダムな文字列を含めたHTMLResponseをクライアントXに返してあげる
→クライアントXは、POSTするときに、普通のFORM DATAとは別に、そのランダムな文字列もFORM DATAとして追加
→サーバ側は、クライアントXに渡したランダムな文字列と、今POSTされた文字列が等しいかチェック
→同じならば認証おk

なんでこうするかというと、
サーバ側が指定したページでない場所からPOSTしようとしても、「ぼくが発行したランダムな文字列もらってないからアクセスできないよ」ということをしたいから。

↓はクソ。

事象

UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.")

はじめに

この{% csrf_token %} とかいうやつは、クロスサイトリクエストフォージェリ対策のためにあるやつ。
テンプレートに書いても動かないし、そもそもテンプレートに書く理由がイミフだったので調べた。
( どうせそれ誰も外さないんだから、元から実装してほs(ry )

Djangoのバージョンは1.7

クロスサイトリクエストフォージェリについて
→『踏み台サイトを用いて対象のサーバに攻撃する手法』

DjangoCSRF対策について

Cross Site Request Forgery protection | Django documentation | Django

CSRF対策をどこでやってるかについては下記Middlewareについてを参照

ぼくは何が間違っていたか

一般的にこのエラーが出たときはcsrf - Django - {% csrf_token %} was used in a template, but the context did not provide the value - Stack Overflow

python - Django : CSRF verification failed even after adding {% csrf_token %} - Stack Overflow

や、上記の公式マニュアルを読めば解決するらしいのだが、
僕はそれでも解決しなかった。
『書いてある通りにやったのに! ナンデ!?』

次はその周辺部で、意味不明だけど使っているようなものはないかと探した。
基本的にハマったときは外殻を見るようにしている。
renderとrender_to_responseがよくわかってなかった。

そもそもrenderってなに。

Combines a given template with a given context dictionary and returns an HttpResponse object with that rendered text.

『テンプレートと与えられたコンテキストディクショナリーを結びつけ、そしてそのレンダリングされたテキストを含んだHttpResponseオブジェクトを返す』
らしいです。
ああね。
HttpResponseは感覚でわかるけどね。うん。

いやいやコンテキストディクショナリーってなんだよ

What is a context in Django? - Stack Overflow

要は、Viewからテンプレートに渡すときに使うディクショナリーってことらしいです。たぶん。

結局render()とは

正直Djangoのソースを見ても実装はよくわからんかった。

render() is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.

と書いてあるので、とりあえず、render_to_responseに、context_instanceの引数をくっつけるとrenderになるっぽい(英語よわい)

Tutorial 3にも地味に書いてあった。つらい。

A shortcut: render()¶

It’s a very common idiom to load a template, fill a context and return an HttpResponse object with the result of the rendered template. Django provides a shortcut.

引用:Writing your first Django app, part 3 | Django documentation | Django

それで?

で、僕が何を間違っていたかというと、

渡す元のView
→テンプレート返すよ!(render_to_responseで)
→ユーザが入力したよ!
→送信!Request!
→いやおまえRequestContextでCSRF対策してないよね!!(render_to_responseにはRequestContextがない(らしい!))
→そもそも渡される側まで到達していないおわた

のに
ずっと渡される側のソースをうんうんひねりながら考えていたことだった。

だ……だって、エラーが渡される側のソースがforbidden!だって言ってくるから……

まあとりあえず解決してなにより。

寝る