以前、CSRFについてのエントリを書きました。
上記エントリではCSRFの概念について書きましたが、もう少しつっこんで調べる必要が出てきました。調べたことを書いてゆきます。
application.rb(ないし適当なController)にprotect_from_forgeryメソッドを定義すれば、railsが自動的にCSRF対策をしてくれます。というか、デフォルトでapplication.rbに下記のように書いてあるので、特に何もせずともCSRF対策はバッチリなのです。
protect_from_forgery# :secret => '8ff3ed33f86a431662d8dfe255acdb4a'
railsは、get以外の動詞のリンクに、authenticity_tokenというパラメータを自動的に付け加えます。get以外の動詞の各アクションでparams[:authenticity_token]とsession[:csrf_id]を比較して、同値であればOKとしているようです。*1同値でなければActionController::InvalidAuthenticityTokenという例外がでます。
protect_from_forgery# :secret => '8ff3ed33f86a431662d8dfe255acdb4a'
上記のコードに書いてある:secretというオプションは、セッションをDBまたはメモリに格納しているときにだけ使います。デフォルトはセッションをクッキーに格納している*2ので、:secretはコメントアウトのままにしておきます。
特定のメソッドだけCSRFの対策をしたくない場合は、そのメソッドのあるコントローラでこんな風に定義します。
protect_from_forgery:except => ["create"]
:onlyも使えます。こうすると、createアクションの時のみprotect_from_forgeryが有効になります。
protect_from_forgery:only => ["create"]
CSRFを詳しく調べた理由は、これがやりたかったから。
先ほども書きましたが、get以外の動詞(POST, PUT, DELETE)を使う時は、authenticity_tokenをセットする必要があります。なのでrailsのajax用のヘルパを使わずに、独自にjavascriptを書いてdbをいじる時は手動でauthenticity_tokenをいれてあげないといけません。また、PUTやDELETEはブラウザが対応していないので、特殊なやり方を取る必要があります。
authenticity_tokenの値を入手するにはform_authenticity_tokenメソッドを使います。こんな感じでhiddenに入れてあげると良いと思います。
<%= hidden_field_tag"authenticity_token" form_authenticity_token %>
まず、railsは、下記のようにputを使うように定義すると
<% form_for:user,:method =>"put"># ...<% end %>
下記のようなHTMLを自動的に作成します。
<input hiddenvalue="put"name="_method" />
そして、リクエストが来たときに、params[_method]の中を見てメソッドを判別しています。なので、javascriptの中で_methodを渡すように書いてあげれば良いです。
まず、viewにauthenticity_tokenをセット。次にjavascriptでこんな感じに書きます(jquery使用してます)。ポイントは、
の二つをrailsに送信しているところ。
$(function(){ $("#hoge").click(function(){ $.ajax({dataType:"text", data:{"_method":"put","authenticity_token": $("#authenticity_token").val()"hoge":"hoge"},type:"POST",cache:true,url:"http://www.example.com/", success:function(data){// ...}})} )});
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。