#概要
railsにおいてCSRF対策の学習中、ヘルパーを使わないとエラーになるとのことで、試しにクロームでlink_toのフォームの検証をしてaタグでdeleteを記述したところ、エラーにならなかったので、いろいろと調べて見ました。
結論は、CSRF対策の本質はlink_toではなく、カスタムデータ属性にありました、ということです。
#問題提起
<%= link_to '削除', "/tweets/#{tweet.id}", method: :delete %>
上記をクロームで検証したところ、
<a rel="nofollow" data-method="delete" href="/tweets/10">削除</a>
となっていました。
CSRF対策ではlink_toとヘルパーをつかうとトークンが発行されて、問題のないリクエストかを判断するとのことでしたので、このaタグに書き換えたらトークンは発行されないのでは? と思い、実際にファイルを書き換えたところ・・・・・。
結局、トークンが発行され、link_toとなにも変わりませんでした。
aタグでもいけるじゃん!
と思ったのが今回いろいろ調べたきっかけです。
※冷静に考えると、クロームでの検証が本物で、ファイルを書き換えて検証結果と同じにすることに意味はなかったのですが、そこのツッコミはご容赦いただきたいです。
#発見した記事
最初に発見した記事です。
link_toで突然methodが効かなくなって困ってるあなたへ
ここからmethodにjQueryが関わっているらしいことがわかりました。
そういえば、aタグにカスタムデータ属性が設定されています。
この辺に、link_toのカラクリがありそうです。
#rails.js
// Handles "data-method" on links such as: |
// <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
handleMethod: function(link) {
var href = rails.href(link),
method = link.data('method'),
target = link.attr('target'),
csrfToken = rails.csrfToken(),
csrfParam = rails.csrfParam(),
form = $('<form method="post" action="' + href + '"></form>'),
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) {
metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />';
}
if (target) { form.attr('target', target); }
form.hide().append(metadataInput).appendTo('body');
form.submit();
},
jquery-ujsのgithubからです。
https://github.com/rails/jquery-ujs/blob/master/src/rails.js
ここからカスタムデータ属性の値を取得してメソッドを決定、またトークンをくっつけていることがわかります。
また、ブラウザがDELETEのHTTPメソッドをサポートしていないことから、
<input type="hidden" name="method" value="delete">
としてform タグから _method を指定してdeleteメソッドを再現していることもわかります。
#まとめ
まだしっかり理解したわけではないのですが、アプリケーション外からのリクエストだとこのrails.jsを通さないのでCSRFを防げるということなのでしょうか。
補足、訂正がありましたら、教えていただけると幸いです!
以下、参考記事。
https://cre8cre8.com/rails/get-post-delete-put-match-routes.rb.htm
https://spitfire-tree.hatenadiary.org/entry/20120323/1332477590