セキュリティなんも分からんけど、勉強の為に今のうちにまとめておこうというもの。
信ぴょう性ゼロの雰囲気記述。
書いてあることが間違っていて、もし私に伝えて下さる心のお優しい方がいらっしゃればご指摘ください。
#CSRFについて考える前に
CSRF。しーさーふって言うらしいです。私はしーえすあーるえふって読んでました
これを理解するために
- リクエストはどこのサイトからどこのサイトへも出来るということ
- クッキーは自動的に送信されてしまうこと
を理解しておく必要があります。理解している人は、CSRFについて考える前に
の章は飛ばして本題から見てください。
では、ぼちぼち書いていきます。
リクエストはどこのサイトからどこのサイトへも出来る
スクール時代に書いていたサイトを出してきました。このサイトをAとします。
もう一個、別のサイトがあります。Bサイトとします。果物の注文を受け取るサイトです。
※Dockerとxamppの環境で超無理やり作りました。私のプログラミングスキルだとこれが限界☆
さあここで質問です。
AサイトからBサイト(つまり全く別のサイト)にリクエストを送って、Bサイトに注文情報を送ることは出来るのでしょうか?
--- answer ---
はい。
出来ます。
この見出しに書いてあるし、そりゃ出来るでしょうねえと思った方。その通りです。
<form action="http://localhost/fruits/xss_submit.php(Bサイト)" method="POST">
<label for="name" class="center-label">名前
<input class="form-control col-8 center-form" name="name">
<label for="kind" class="center-label">果物の種類
<input class="form-control col-8 center-form" name="kind">
<label for="amount" class="center-label">希望の量
<input class="form-control col-8 center-form" name="amount" type="number">
<div class="row justify-content-center my-2">
<input type="submit" value="申込する" class="btn btn-info col-4 my-5">
</div>
</form>
みたいなコードを書いて、リクエストを送ってみます。
やってみましょう。
↓Aサイトの申込するボタンクリック!
はい。Bサイトにtest様よりりんごを4個承りました!と出ました。
AサイトからBサイトにリクエストが飛んで、そのリクエストが実行されていることが分かりますね(*'▽')
Railsだとform_withで書くからあんまり実感ないかもしれないですが、自分のサイトからだけでなく、どこからでもリクエストは出来るよ~というのを何となく覚えておいてください。
クッキーは自動的に送信されてしまうこと
HTTPはステートレスで~セッション管理が~~というのは何となく聞いたことがあるかもしれません。それです。
ここでは超ざっくり書きます。
HTTPはステートレスなので、以前にやりとりした情報を覚えていません。
例えば、私がTwitterで「暇だな」「セキュリティなんも分からん」「ねむ」ツイートをしようと思った時、クッキーによるセッション管理が無かったら
私のidは"nurumayusayu"です。パスワードは"xxxxxxxxxx"です。ツイートは"暇だな"です
私のidは"nurumayusayu"です。パスワードは"xxxxxxxxxx"です。ツイートは"セキュリティなんも分からん"です
私のidは"nurumayusayu"です。パスワードは"xxxxxxxxxx"です。ツイートは"ねむ"です
みたいな感じで、毎回認証情報のidとパスワードを送る必要が出てきます。
それは面倒だなあということで(これは私の主観。起源は知らない)、クッキーにセッションIDを保存してそれを送ることでログイン時に認証したnuyumayusayuだな。と認識してくれるようになっています。
私のセッションIDは"23sd4rftgyhuji56t7yhuji"です。ツイートは"暇だな"です
私のセッションIDは"23sd4rftgyhuji56t7yhuji"です。ツイートは"セキュリティなんも分からん"です
私のセッションIDは"23sd4rftgyhuji56t7yhuji"です。ツイートは"ねむ"です
と、クッキーに保存されているセッションIDを送ることでセッションID="23sd4rftgyhuji56t7yhuji"が送られてきたからこのリクエストはnurumayusayuさんからだ
とサーバが認識してくれます。
これは誰が送っているの?というと、自分が使っているブラウザ(Chromeとか)が勝手に送ってくれています。
ディベロッパーツールのCookieのところを見れば、イメージが付きやすいかも。Qiitaについているクッキーも、リクエストの際にブラウザが勝手に送ってくれることで、この操作をしているのはさゆさんだ!
とQiitaが認識しているわけですね(*'▽')
というわけで、私がどう思っていようが、リクエストの時にはブラウザが自動的にクッキーを送信するよ~というのを何となく覚えておいてください。
(ブラウザでCookieブロックの設定をしているとか、SameSite属性とかはまったく無いと仮定しているよ!)
本題CSRFについて
さあ、先ほどの前提はこれです。
- リクエストはどこのサイトからどこのサイトへも出来る
- クッキーは自動的に送信されてしまう
これを踏まえて、さあ、また質問です。
【質問前提(空想)】
- クッキーに保存されているセッションIDのみでセッション管理(これは○○さんだと判断するための手段)をしているTwitterっぽいサイト、「ツイッタッタカター」というサイトがあります。(セッションにはSameSite属性もRefererによる確認も無いとします)
- Cサイトの
/trap
ページには、onloadされたら(このページのリソースが読み込まれたら)「眠くて草」とツイートするようツイッタッタカターにリクエストしてね
というformが用意されています
【質問】
自分がツイッタッタカターにログインしている時に、Cサイトの/trapページにアクセスしたら、どうなるでしょうか?
--- answer ---
ツイッタッタカターには自分の名前で「眠くて草」とツイートされます
・・・???となったと思うので、ツイートされた手順を書きます
- 自分(さゆさんとする)がツイッタッタカターにログイン。クッキーにセッションID(twettattaID=3edrftgyhuj)が保存される
- 自分がCサイトの/trapページにアクセスする
- ブラウザはCサイトのリクエストに従って、「眠くて草」とツイートするというリクエストを__クッキーに保存してあるセッションID(twettattaID=3edrftgyhuj)付き__でツイッタッタカターに送る
- ツイッタッタカターは「twettattaID=3edrftgyhujのセッションIDはさゆさん」と認識して、さゆさんとして「眠くて草」とツイートする
- 私「よくわかんないんだけど勝手にツイートされてる!!」
という手順です。
自分はonloadで勝手にリクエストを送らされているのに、ブラウザが勝手にクッキーを送るので、サーバ側は「クッキーのセッションIDでさゆさん本人からのリクエストだと認識☆」として処理をする。
これがCSRFのざっくりした説明です。
クッキーの機能によって「させられてるリクエスト」であります。でもクロスサイトリクエストフォージェリというのは日本語訳すると偽装リクエストと習ったけど伝わりにくいしゴニョゴニョ・・・
例に出したのはツイートですが、これがパスワード変更だったり、重要な処理のリクエストだったら怖いよねーという話。
じゃあ最後の質問
CSRFは「リクエストを自分のアカウントとしてさせられること」
だと分かりました。では、Dサイトにアクセスしたことで勝手にS企業のお問い合わせフォームを送らされる行為はCSRFでしょうか?
(S企業のお問い合わせフォームはログインとかなしに誰でも送れるよ!)
--- answer ---
これはCSRFではないです。
「おっ、誰かから嫌がらせが来たな」となると思いますが、CSRFではありません。だって私が書いたってならずに誰かから問い合わせ来たなってだけですから。
でも匿名掲示板などのIPアドレスで識別している場合はどうなの!?というのは、IPAに資料がありました(p18あたり。すごい分かりやすいし面白い。。。)
https://www.ipa.go.jp/files/000017508.pdf
資料を見て「うんうん、その通りだね♪」となったらきっとあなたはCSRFマスター、ならなかったら私の記述不足です。
対策としてtokenを使ったりしますよーと書かないと、と思いつつ、ちょっとtokenのことについて書くほどの気力は無くなった。。。気力が戻ったら書くかもです。でもIPAの資料見た方が正確かも、うん。
以上!
あくまで雰囲気で理解するための記事なので、正確な部分はほかの記事(↓とか)をご参照くださいm(_ _)m
また、間違っていたら、ご指摘いただけると嬉しいです。