ドキュメントを読み込むのは大事、ということでRailsガイドを頭から読んでいく取り組みをしています。 各章ごとに、(Railsガイドにちゃんと書いてあるのに)知らなかった機能を雑にまとめていきます。
今回は、Rails セキュリティガイドの章です。今回はセキュリティの話なので、知らなかったものと合わせて、改めて頭に入れておくべきと思った内容も含めてメモしました。
セッション固定攻撃の対策
リンクはこちら
最も効果的な対応策は、ログイン成功後に古いセッションを無効にし、新しいセッションIDを発行することです。
devise
gemを見てみると、sign_in
時にセッションを一度捨てる処理がされています。
# lib/devise/controllers/sign_in_out.rb def sign_in(resource_or_scope, *args) # ...(略) expire_data_after_sign_in! # ... end private def expire_data_after_sign_in! session.keys.grep(/^devise\./).each { |k| session.delete(k) } end
ファイルのダウンロード機能の注意
リンクはこちら
ファイルダウンロードをする際に、ダウンロードパスにparamsの値を含める場合は../../xxx
などのparamsで悪さをされないように、構築されたダウンロードパスとアプリ側が想定しているパスが一致するかを検証する必要があります。
結構うっかりしてしまいそうな箇所にも思うので、知識としてしっかり頭に入れておかないといけないですね。
アカウント総当たり攻撃に対する対策
リンクはこちら
Webアプリケーションの設計でおろそかにされがちなのは、いわゆる「パスワードを忘れた場合」ページです
ついついユーザーの目先の便利さを求めて「指定されたメールアドレスは存在しません」といった内容にしてしまいそうですが、これは攻撃者にとってはヒントになるので危ないということですね。
ただ、ユーザーがtypoした場合などもあるので、そういった際に本当に困っているユーザーが自主的に気付けるようにする仕組みが必要そうです。
メールの変更にもパスワードを要求するべし
リンクはこちら
アカウントのメールアドレスを変更する攻撃を仕掛けることでパスワードをお忘れですか?からアカウントを乗っ取るということができてしまうので、メールアドレスを変更する際にもパスワードを要求するべしという内容です。
パスワード変更の際に旧パスワードを要求するのは当然必要として忘れないと思いますが、メールアドレスの方は漏れやすいようにも思いました。
正規表現
リンクはこちら
Rubyの^や$は、入力全体の冒頭と末尾ではなく「行の」冒頭と末尾にマッチしてしまうので、
\A
や\z
を使うべしという内容です。
これは知らないとすぐ踏んでしまうと思います。
str = "javascript:exploit_code();/*\nhttp://hi.com\n*/" str.match?(/^https?:\/\/[^\n]+$/i) #=> true str.match?(/\Ahttps?:\/\/[^\n]+\z/i) => false
ヘッダーインジェクションの対策
リンクはこちら
ヘッダーの情報も比較的容易に操作できてしまうので、User-Agent
を管理者画面でエスケープなしで表示するなどしてはいけないという内容です。
また、referer
もそのまま使うと危ないので適切な対処が必要です。
DNSリバインディングの対策
リンクはこちら
DNSリバインディングをきちんと理解できていなかったので、これを機に調べました。
罠サイトはユーザーが一度アクセスした直後に別のIPアドレスを返すように変更し、「信頼された」状態となったブラウザを通じてユーザーの内部ネットワークなどにアクセスします。
Railsでは、Rails.application.config.hosts
で許可するホストを制限することでDNSリバインディング対策を実施します。
deep_mungeで安全でないクエリ生成を防止
リンクはこちら
意図しないクエリを発行しないようにしているのがdeep_munge
メソッドです。
munge
はdeeplだと翻訳が出ませんでしたが、weblioだと「コードを難読化する」という意味が表示されました。
config.action_dispatch.perform_deep_munge = false
を設定してJSONで{ "person": null }
のパラメータを送信した時
params #=> {"person":[null], ...}
config.action_dispatch.perform_deep_munge = false
を設定せずにJSONで{ "person": null }
のパラメータを送信した時
params #=> {"person":[]... }
CORS
リンクはこちら
Rack CORSミドルウェアによってCORSを有効にできます。
Railsガイドの例のように設定してから以下のようにcurlでレスポンスヘッダーを確認すると、access-control-allow-origin
などが設定できていることを確認できました。
$ curl -I -X OPTIONS http://localhost:3000 -H 'Origin: http://example.com' ... access-control-allow-origin: http://example.com access-control-allow-methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD ...