なにこれ
体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(以下、得丸本とする)という本に「リダイレクト処理にまつわる脆弱性」いう項目がある。本記事では、それに基づいて、安全なオープンリダイレクトを Ruby on Rails で実装してみることとする。なにがやりたいのかというと、ログインページにジャンプしても元のページに戻れる仕組みををつくっていくのである。
コードについて
- 今回のコードは Github のレポジトリ にもあります
- url に使えない文字を防ぐために、base64にエンコードしてあります
-
example.com
という架空の URL のサービスを考えることにします
アジェンダ
得丸本いわく、以下のポイントがあると脆弱性の原因となるそうです。
- リダイレクト先の URL が
example.com
以外の URL であってもリダイレクトする -
http://example.net/example.com
みたいなホスト名を含めた url をすり抜けさせる -
//example.com
みたいな https と http 以外のスキーマも認める
出来上がったコード
# coding: utf-8
require 'uri'
class ContiuneFromPreviousPagesController < ApplicationController
HOST_URI = 'example.com'
def show
uri = Base64.urlsafe_decode64(params[:id])
parsed_uri = URI.parse(uri)
# (1)(3)
if parsed_uri.host.split('.')[-2..-1].join('.').downcase == HOST_URI && %w[http https].include?(parsed_uri.scheme)
redirect_to uri
else
head :not_found
end
rescue NoMethodError # そもそも uri じゃない文字列を除外する
head :not_found
rescue URI::InvalidURIError # "iiii" とか防止
head :not_found
end
end
問題(1)の対策
この問題は要は他所の url を弾けば良いので、example.com
以外のサイトを無視すれば良い。つまり google.co.jp
とかのアカウントをうけたら、404 を返してやれば良い。文句を言われたら「仕様です」と答える。よって、解決済み。
問題(2)の対策
得丸本では正規表現を使っていたけど、この記事では Ruby の uri ライブラリを使ったので、このコードでは問題とならないようにした。よって、解決済み。
問題(3)の対策
https と http だけにスキーマを限定した。よって、解決済み。
テストについて
一応は自動テストも書いてみたので、興味がある方は見てみてください。
おわりに
正規表現まわりのミスはセキュリティホールにつながる感じがする、と思いました。