CSRF
Webアプリケーションには、利用者自らの操作では取り消しのできない重要な処理がある。ここでいう「重要な処理」とはECサイトでのクレジットカードでの決済やメールの送信、パスワードの変更などのことをいう。
こういった重要な処理の過程で不備があると、クロスサイトリクエストフォージェリ(以下CSRFと省略)の脆弱性が生じる場合がある。CSRFは「シーサーフ」もしくは「シーエスアールエフ」と呼ぶ。
CSRF(クロスサイトリクエストフォージェリ)
掲示板への投稿やメールの送信、ECサイトでの商品購入など本来外部より実行されてはいけない重要な処理を、なんらかの攻撃手法を用いて実行させてしまうという攻撃手法であるCSRF(クロスサイトリクエストフォージェリ)の概要と対策方法を考える。
CSRFとは
Webサイトにスクリプトや自動転送(HTTPリダイレクト)を仕込むことによって、利用者に意図せず別のWebサイト上で何らかの操作(掲示板への書き込みや銀行口座への送金など)を行わせる攻撃手法のこと。
CSRFの脆弱性が存在すると以下のような被害を被る可能性がある。
- 利用者のアカウントによる物品の購入
- 利用者の退会処理
- 利用者のアカウントによる掲示板への書き込み
- 利用者のパスワードやメールアドレスが変更
CSRF脆弱性の影響は「重要な処理」の悪用に限られるため、CSRFの脆弱性を個人情報の取得等に用いることはできない。
CSRFの攻撃例
利用者が罠サイトを閲覧することによってパスワードが変更されてしまう例を見てみる。
- 利用者がexample.jpにログインしている
- 攻撃者は罠を作成
- 利用者が罠を閲覧する
- 罠のJavaScriptによる、被害者のブラウザ上で攻撃対象サイトに対し、新しいパスワードabcdefがPOSTメソッドにより送信される
- パスワードが変更される
CSRFの対策
一般的な対策方法
CSRF攻撃を防ぐには、「重要な処理」に対するリクエストが利用者の意図によるものかどうかを確認することが必要になる。
このためCSRF対策としては、以下の2点が考えられる。
CSRF対策の必要なページを区別する
CSRF対策はすべてのページに行う必要はない。むしろ、対策の必要がないページの方が多い。対策に必要なページは、他のサイトから勝手に実行されては困るようなページである。例えば、ECサイトの物品購入ページや、パスワード変更など個人情報の編集確定画面などが挙げられる。
CSRFの対策としては、まず実装するWebアプリケーションのどのページに脆弱性対策が必要なのか設計段階で明らかにすること。
以下の図のように、機能一覧の中でCSRFの対策が必要なページを色分けすると良い。
正規利用者の意図したリクエストを区別できるように実装する
CSRF対策で必要なことは、正規利用者の意図したリクエストなのかどうかということ。
ここでの意図したリクエストとは、利用者が対象のアプリケーション上で「実行」ボタンなどを押して、「重要な処理」のリクエストを発行することをいう。
正規のリクエストかどうかを判断する方法は3種類ある。
- 秘密情報の埋め込み
- パスワードの再入力
- Refererのチェック
Refererによるチェックは少し難しいので、上の二つについて説明する。
秘密情報の埋め込み
登録画面や注文確定画面などのCSRF攻撃への対策が必要なページに対して、第三者の不正利用者が知り得ない秘密情報を要求するようにすれば、不正リクエストによる重要な処理が実行されることはない。このような目的で使用される秘密情報のことをトークンという。
パスワードの再入力
こちらは文字通り重要な処理が確定する前に、再度パスワードを入力してもらう。これはCSRF対策の他にも物品の購入などに先立って、利用者の意思の念押しをしたり、共用のPCにおいて正規の利用者以外の利用者が、重要な処理を実行するのを防いだりする効果がある。
CSRFの攻撃例として、とりあげたパスワード変更ページにも現在のパスワードを再入力させることによりCSRF攻撃を防ぐことが可能。
しかし、対策が必要なページ以外でパスワードの再入力を求めるページが複数あると煩雑なアプリケーションになってしまうため、注意が必要。
RailsでのCSRF対策方法
RailsではどのようにCSRF対策を行っていけばいいのか?
実は、Rails側できちんと対策を行ってくれている。基本的には開発者はなにもしなくても大丈夫である。
それでは実際にRailsがどのようにCSRF対策を行っているのか。
/projects/pictweet/app/controllers/application_controller.rb
を開く。
1 2 3 4 5 6 7 8 9 10 11 |
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :nickname
end
end
|
protect_from_forgery with: :exception
記述がある。これがRailsアプリケーション内でCSRF対策を行うというという命令になる。こちらをすべてのコントローラの親であるapplication_controller.rbに記述することによって、その子コントローラすべてに先ほど説明したようなCSRF対策をRails側で行ってくれる。
具体的には、まずサイトのHTMLに一意のトークンを埋め込む。これと同じトークンを、セッションcookie(クッキー)にも保存している。ユーザーがPOSTリクエストを送信すると、HTMLに埋められているCSRFトークンも一緒に送信される。あとは、サーバ側でページのトークンとセッション内のトークンを比較し、両者が一致することを確認したらリクエストを受け付ける。