たくろぐ!

世界一のチラ裏

RailsにおけるAuthenticity Token(CSRF対策用トークン)について翻訳してみた

はじめに

トークンという普段生活していて馴染みのない言葉を調べてみた。

仮想通貨とかやってると知ってる人がいるらしいけど、僕はつい最近までよくわかっていなかったのでいい機会だと思ってStackoverflowのAuthenticity Tokenの英語の説明を翻訳してみた(意訳含む)。

ソースは以下。

stackoverflow.com

では早速やってみるぞ。

質問

I am running into some issues regarding the Authenticity Token in Rails, as I have many times now.

But I really don't want to just solve this problem and go on. I would really like to understand the Authenticity token. Well, my question is, do you have some complete source of information on this subject or would you spend your time to explain in details here?

私は今やRailsCSRF対策用トークン(Authenticity Token:本来の意味は「信頼性トークン」)に関する問題に何度も直面しています。

この問題をただ解決したり、見過ごしたくはありません。CSRF対策用トークンを本当に理解したいのです。本題ですが、質問です。ここにいる方で、この議題に関しての良質な情報源をお持ちか、または詳細について説明してくださる方はいますか?

回答

何が起こっているか?

What happens

When the user views a form to create, update, or destroy a resource, the Rails app creates a random authenticity_token, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for the authenticity_token, compares it to the one stored in the session, and if they match the request is allowed to continue.

ユーザーがリソース(Railsアプリが扱うデータ)を生成、更新、削除するためのフォーム画面を閲覧しているとき、RailsアプリケーションはランダムのCSRF対策用トークンを生成し、セッションに保存し、フォームの隠しフィールドに設置します。ユーザーがこのフォーム(に入力し、これ)を送信するとRailsCSRF対策用トークンを探し、セッションに保存されているものと比較し、もし合致していればクライアントとの通信を保持します。

なぜこのようなことが起こるのか?

Why it happens

Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself. Imagine that you are using service A, you logged into the service and everything is ok. Now imagine that you went to use service B, and you saw a picture you like, and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to http://serviceA.com/close_account. This is what is known as CSRF (Cross Site Request Forgery).

CSRF対策用トークンがセッションに保存されるとき、クライアント(Chromeなどのブラウザのこと)はその値を知ることはできません。これは他人がRailsアプリ自体にあるフォームを見ることなくアプリへフォームを送信するのを防ぐためです。サービスAを使うことを想像してください。あなたはサービスにログインし問題がないことを確認します。では次にサービスBを使うようになったのを想像してください。あなたは好きな写真をみたり、大きく引き伸ばしたりします。そこでもしそのサービスBに悪意のあるコードがあればあなたがログインしていたサービスAに http://serviceA.com/close_account というようなリクエストを送信して、アカウントを削除するよう問い合わせするかもしれません。これがよく知られているクロスサイトリクエストフォージェリCSRF)というものです。

If service A is using authenticity tokens, this attack vector is no longer applicable, since the request from service B would not contain the correct authenticity token, and will not be allowed to continue.

もしサービスAがCSRF対策用トークンを使っているなら、サービスBからのリクエストに正しいCSRF対策用トークンが含まれていないのでこの方向(B→A)の攻撃は適用されず、リクエストを継続することはできません。

API docs describes details about meta tag:

APIドキュメントにはメタタグに関しての詳細が記載されています。

CSRF protection is turned on with the protect_from_forgery method, which checks the token and resets the session if it doesn't match what was expected. A call to this method is generated for new Rails applications by default. The token parameter is named authenticity_token by default. The name and value of this token must be added to every layout that renders forms by including csrf_meta_tags in the HTML head.

CSRF対策はCSRF対策用トークンをチェックしてくれる protect_from_forgery メソッドで動作し、もし想定しているトークンと合致しない場合セッションを削除してくれます。このメソッド呼び出しは最新のRailsアプリケーションではデフォルトで生成されます。このトークンパラメータはデフォルトでは authenticity_token と名付けられています。このトークンの名前と値はHTMLヘッダーに csrf_meta_tags を含めることによってフォームをレンダリングするどのレイアウトにも挿入されているはずです。

注記

Notes

Keep in mind, Rails only verifies not idempotent methods (POST, PUT/PATCH and DELETE). GET request are not checked for authenticity token. Why? because the HTTP specification states that GET requests is idempotent and should not create, alter, or destroy resources at the server, and the request should be idempotent (if you run the same command multiple times, you should get the same result every time).

RailsはPOSTやPUT/PATCH、DELETEのような冪等(べきとう:後述)性を持つメソッド以外のもののみ検証することを覚えておいてください。GETでのリクエストはCSRF対策用トークンではチェックされません。なぜでしょうか?それはHTTP通信の特徴は「GETリクエストは冪等性を持ち、サーバ内のリソースの生成や変更、削除するべきではない」ということを物語っているからです。それがリクエストが冪等的(同じコマンドをいつ何度やってもその度に全く同じ結果が返るべきであるということ)であるということです。

※注釈:「冪等的」という言葉はあまり使われません。うまく訳できませんでした。どげざ。

Also the real implementation is a bit more complicated as defined in the beginning, ensuring better security. Rails does not issue the same stored token with every form. Neither does it generate and store a different token every time. It generates and stores a cryptographic hash in a session and issues new cryptographic tokens, which can be matched against the stored one, every time a page is rendered. See request_forgery_protection.rb.

また最初に定義されている実際の実装は少し複雑ですが、強固なセキュリティを保証します。Railsはどのフォームであっても保存されているトークンと同じトークンを発行しません。また毎回異なったトークンを生成したり保存したりもしません。Railsはセッションに毎回ページがレンダリングされるたびに(以前)保存されたものとは一致しない暗号化された新しいハッシュを生成・保存します。詳しくは request_forgery_protection.rb をご覧ください。

練習

Lessons

Use authenticity_token to protect your not idempotent methods (POST, PUT/PATCH, and DELETE). Also make sure not to allow any GET requests that could potentially modify resources on the server.

冪等性を持たないメソッド(POST, PUT, PATCH, DELETE)を保護するためにCSRF対策用トークンを利用してください。またサーバーのリソースを変更しうるGETリクエストを通さないことも確認してください。

まとめ

トークンってピクミンみたいなかわいい生物の名前っぽい響きだよね?

今日も平和な世界!!

オワオワリ。