CSRFに関する学習メモ

## 学習背景

現職でRailsを使用しており、他の方が書かれたコードに`protect_from_forgery`という記述がありました。`protect_from_forgery`を調べてみると、CSRF対策のためと記載があり、そういえばCSRFってなんでしたっけ？ということで調べてみました。

## CSRFについて

CSRFとはクロスサイト・リクエスト・フォージェリの略で、フォージェリとは「偽造品」という意味があります。

CSRFについて[ウィキペディア](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA)で以下のように説明されています。

>CSRF脆弱性とは以下のような攻撃（CSRF攻撃）を可能にする脆弱性を指す[1]：攻撃者はブラウザなどのユーザ・クライアントを騙し、意図しないリクエスト（たとえばHTTPリクエスト）をWebサーバに送信させる。

例えば、ショッピングサイトにログイン状態で悪意のあるユーザが作ったサイトをクッリクすると、ショッピングサイトにログインしたユーザのメールアドレスやパスワードを悪意のあるユーザが指定したものに変更されてしまいます。

「悪意のあるユーザが作ったサイト」とは、どんなサイトなんだろう？？

例えば、ショッピングサイトでパスワードを変える際には以下の流れがあったとします。
①パスワード変更画面で新しいパスワードを変更する。（簡単ですが、以下のようなイメージです。。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673263/f8d2046e-e563-e87a-cf3c-216cbb4b17db.png)


②パスワードを変更したことをユーザに通知する画面(（こちらも簡単ですが、イメージです。。）)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/673263/6bdbcb95-1a5f-f570-9d29-5f2254840895.png)


上記のようなショッピングサイトにログイン中のユーザが悪意のあるサイトをクリックすると、上記サイトのパスワードを変更されてしまうサイトです。例えば以下のようなコードです。

```html
<body　onload="document.forms[0].submit()">
<form action="http://hogehoge/45" method="POST">
<input type="hidden" name="pwd" value="hogehoge">
</body>
```

以下のJavascriptのコードで悪意のあるページを開いた瞬間にフォームの中身がサーバ側に送信されてしまいます。
```html
<body　onload="document.forms[0].submit()">
```

送信先は適当に`http://hogehoge/45`とショッピングサイトのパスワードを変更する処理に向けたURLを指定します。

```html
<form action="http://hogehoge/45" method="POST">
```

`value="hogehoge"`で悪意のあるユーザが決めたパスワード`hogehoge`に変更されます。

```html
<input type="hidden" name="pwd" value="hogehoge">
```


## CSRF対策

3点あります。
①パスワード変更画面で新しいパスワードを送信する際にトークンを発行して、悪意のあるサイトからの送信ではないかを確認する。
②パスワードを変更する前にユーザIDとパスワードを入力させてから、パスワード変更を可能にさせる。
③パスワード変更画面から送られてくるリクエストURLをコントローラー側で見て、そのURLが悪意のあるサイトからのURLではないかをチェックする。正規ユーザがパスワード変更画面から変更したものであるかをチェックする。


①についてですが、パスワード変更画面に実装するのは、例えば以下のようなコードです。

```html
<form action="changepassword" method= "post">
  新しいパスワード<input name="pwd" type="password">
  <input type="hidden" name="authenticity_token" value="<token_value>">
</form>
```

`value="<token_value>"`でトークンをコントローラー側に送信して、コントローラー側でビュー側で送られてきたトークンをチェックすることで、悪意のあるユーザによるパスワード変更を防ぎます。

```html
<input type="hidden" name="authenticity_token" value="<token_value>">
```

今回疑問に思ったきっかけである`protect_from_forgery`は①のCSRF対策に該当します。
[Railsセキュリティガイド](https://railsguides.jp/security.html)を読むと、`protect_from_forgery`はデフォルトで設定されているとのことです。また、コントローラー側に`protect_from_forgery`の記載不要だけでなく、ビュー側にもトークンを発行する処理が不要とも書かれてあり、開発者にとってはとてもありがたいです。

>以下の1行コードはアプリケーションのコントローラに追加するものであり、Railsで新規作成したアプリケーションにはこのコードがデフォルトで含まれます。
>
> `protect_from_forgery with: :exception`
このコードがあると、Railsで生成されるすべてのフォームとAjaxリクエストにセキュリティトークンが自動的に含まれます。


## 感想
Railsのようなフレームワーク側でセキュリティ対策してくれているのはありがたいな、と思いました。また、他のセキュリティ対策についてもRails側でどのような対策をされているのかについても深く理解していきたいと思いました。 



## 参考文献

この記事は以下の情報を参考にして執筆しました。

- 書籍「安全なWEBアプリケーションの作り方」
- [RailsのCSRF対策について](https://qiita.com/eshow/items/915f8e8ad317aa8e49a6)
- [ウィキペディア](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA)
- [Railsセキュリティガイド](https://railsguides.jp/security.html)
- [クロスサイトリクエストフォージェリ（CSRF）はサイバー攻撃の「名脇役」? 脆弱性診断におけるCSRFの検出頻度と対策](https://www.sqat.jp/tamatebako/12249/)