2019年に入ってから、安全なWebアプリケーションの作り方の輪読会に参加させて頂いています。
知っているつもりで知らなかったお話も多く、また人と話すことで深掘りができて、コーディング中もヒヤリ・ハットが少しできるようになってきました。
(ただ、自分の目だけだと見落としがちなので、ツールやレビューによるチェックが1番だと思っています)
先日はCSRF(CrossSiteRequestForgery)
対策についてまとめていました。
Rails
のCSRF
対策といえば、ApplicationController
に書いてあるprotect_from_forgery
。
どんなことしてるんだろう、とふと気になったのでコードを読んでいたのですが、そこで驚いたのが、コメントの秀逸さ。
rails/request_forgery_protection.rb at master · rails/rails · GitHub
約50行に渡ってコメントが記載されているのですが、CSRF
からどうやってアプリを守るか、Rails
の方針は何かが平易でわかりやすい言葉で書かれています。
その明確さ、方針のきれいさに読んでいて感動したので、THE・意訳をしてみました。
レンダリングされるHTMLにtokenをふくめることでControllerは守られてるよ
- このtokenは攻撃者には知られないしランダムな文字列だよ
Rails
はセッションに保存したtokenとリクエストのtokenがあってるか比較してるよ- GETリクエスト(べき等であるべきリクエスト)は保護しないよ
- (だから大事な処理はぜったいPOSTにして(GETにしないで)ね)
- でも
JavaScript
やHTML
のリクエストも含めて、セッションに基づく全リクエストはCSRF
で保護されるべきだよGETリクエストは保護しない(だって、大事な処理はGETに書かないって決めたから)けど、 罠サイトが
<script>
タグをつかってあなたのアプリのJavaScript
を呼び出して、データ漏洩しちゃうかもしれない。
だから、XmlHttpRequest
(XHR
とかAjax
っていうよね)だけがJavaScript
によるGETリクエストに答えられるようにしてるよ。XMLHttpRequestとは
スキーム,ドメイン,ポート(これをまとめてオリジンと呼びます)すべてが一致したURLとしか通信できない(リクエストのこと)
そのtokenの埋め込みはどうしているのかというと、これもまた明確に記載されています。
# application.html.erb <head> <%= csrf_meta_tags %> </head> # For AJAX requests other than GETs, extract the "csrf-token" from the meta-tag # and send as the "X-CSRF-Token" HTTP header. # If you are using jQuery with jquery-rails this happens automatically. # 超意訳・再び # GET以外のAjaxリクエストの場合はmetaタグから 'csrf-token' を抽出して # 'X-CSRF-Token' HTTPヘッダーとして送信するよ # jquery-rails(ライブラリ)でjQueryを使用してたら自動でやっとくよ〜😇
最後に、APIのCSRF対策ってどうするんだろう?やっぱりクライアント側でするんだよね…?と気になったのですが、これもまた明記されていました。
# We may want to disable CSRF protection for APIs since they are typically # designed to be state-less. That is, the request API client will handle # the session for you instead of Rails. # APIのCSRFprotectionは無効にしたいよね~ # だってAPIって基本ステートレスだよね # つまり、RailsじゃなくてリクエストAPIクライアントがセッションを処理するんだよ!
Railsの哲学に触れて感動したお話でした!