スポンサーリンク

2015年6月12日

Elixir+Phoenix - InvalidCSRFTokenErrorを対処するだけの簡単なお仕事!

#目的

InvalidCSRFTokenErrorの対処方法を記述する。


#実施環境
OS: Windows8.1
Erlang: Eshell V6.4
Elixir: v1.0.4
Phoenix Framework: v0.13.1

#目次
1. エラー内容について
2. 対処方法について
3. まとめ

#参考文献
http://stackoverflow.com/questions/28595153/phoenix-invalid-csrf-cross-site-forgery-protection-token-error
http://phoenix.thefirehoseproject.com/5.html
https://gist.github.com/chrismccord/cf51346c6636b5052885

#始める前に
昨日、Elixir+Phoenixで掲示板(もどき)を作成していたのですが、
ちょっと、ど嵌まりした実行時エラーがあったので、
アプリケーションは作成途中ですけど記事を上げます。

問題は、HTTPメソッド:Postでページ遷移を行う時に起きた。

##1. エラー内容について

エラー内容は以下の通り・・・
----
(Plug.CSRFProtection.InvalidCSRFTokenError)
Invalid CSRF (Cross Site Forgery Protection) token.
Make sure that all your non-HEAD and non-GET requests
include the csrf_token as part of form params or
as a value in your request's headers with the key 'x-csrf-token'
----

ようは、無効なCSRFのトークンですって言ってる。
そりゃそうだ、設定した覚えないですもの。

CSRFについてはWikipediaを参照すること
クロスサイトリクエストフォージェリ - Wikipedia

##2. 対処方法について
駆逐してやる!エラーなんて一つ残らず駆逐してやる!!

対処方法は2つ(本来は3つだが・・・内容が重複するので)
-1 /web/router.exにある"plug :protect_from_forgery"の設定をなくす。
-2 テンプレートでトークンを設定する。(記述方法が2つある)

まず、一つ目の方法。
/web/router.exを開いて、以下の部分から"plug :protect_from_forgery"を削除。
(コメントアウトでもおk)

※セキュリティの面を見るならあまり良くないと思うけど・・・

----
pipeline :browser do
  plug :accepts, ["html"]
  plug :fetch_session
  plug :fetch_flash
  plug :protect_from_forgery ←これ
end
----

参考: http://hexdocs.pm/phoenix/Phoenix.Controller.html#protect_from_forgery/2

次、二つ目
例えば、/helloと言うページへPostでページ遷移させる時、
以下のように記述すると思う。(ソースは該当部分だけ)

エラーの出る記述
----
<form method="post" action="/hello">
  <input type="submit" value="hello">
----

上記を以下のような記述に変更する。

エラーの出ない記述
----
<form method="post" action="/hello">
  <input type="hidden" name="_csrf_token" value="<%= get_csrf_token() %>">
  <input type="submit" value="hello">
----

やっていることは簡単ですね。
隠しデータで、CSRFのトークンを送っている。

"<%= get_csrf_token() %>"だが、トークンを取得するviewのヘルパー関数を利用している。

/web/web.exのviewの部分でインポートしている。
(ここのview部分に記述するとviewの全てに反映される)

いつのバージョンかは知らないが、get_csrf_token/0の関数がなかったので、
自分でセッションから取得したり、ヘルパー関数自体を自分で定義したりしてたらしい・・・

この記述
----
import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
----

また、v0.9(?)、v0.10(?)あたりのアップグレードで
以下のような記述にてCSRFトークンを送れるようになったらしい・・・
(こちらの方がすっきりしてますね!!)

Phoenix的(?)な記述
----
<%= form_tag("/hello", method: :post) %>
  <input type="submit" value="hello">
----

##3. まとめ
意外と嵌ったエラーだった。
そもCSRFって何?とか、どうやって送るの?とか、知識と経験がないからちょっと手こずった。
でも、探せば同じ問題で記事または質問を上げている人が見つかる内容だったので、
そこまで難題でもなかったかな。

ものによっては、ガチで記事皆無とかあるからな~(Elixir+Sheriffとか、Elixir+Sheriffとか・・・)

ちなみに、Railsでもトークンは送っていたはず・・・
そこら辺から切り口にすればもうちょい楽だったかもしれない。

と言うわけで、皆さんも気を付けて下さい~ノシ

#管理人の独り言~
昨日、"Sapporo Beam"に参加しました。
その時に話題の一つとして出ていたのですが、
なんと!Elixirにて、Sinatra風フレームワークがあることを聞きました。
"trot"と言うそうです。

リンク: https://github.com/hexedpackets/trot

掲示板(もどき)の作成終わったら、早速手を出してみようかと思います。

正直な話、私が行うプログラム規模だと、
Phoenixほどのフレームワークはいらないんじゃないかと思うわけです。
なので、そちらにメインのフレームワークを移すかもしれません。(使えれば・・・)

人気の投稿