LoginSignup
3
0

More than 3 years have passed since last update.

Rails でオープンリダイレクトを実装する

Posted at

なにこれ

体系的に学ぶ 安全なWebアプリケーションの作り方 第2版(以下、得丸本とする)という本に「リダイレクト処理にまつわる脆弱性」いう項目がある。本記事では、それに基づいて、安全なオープンリダイレクトを Ruby on Rails で実装してみることとする。なにがやりたいのかというと、ログインページにジャンプしても元のページに戻れる仕組みををつくっていくのである。

コードについて

  • 今回のコードは Github のレポジトリ にもあります
  • url に使えない文字を防ぐために、base64にエンコードしてあります
  • example.com という架空の URL のサービスを考えることにします

アジェンダ

得丸本いわく、以下のポイントがあると脆弱性の原因となるそうです。
1. リダイレクト先の URL が example.com 以外の URL であってもリダイレクトする
2. http://example.net/example.com みたいなホスト名を含めた url をすり抜けさせる
3. //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 だけにスキーマを限定した。よって、解決済み。

テストについて

一応は自動テストも書いてみたので、興味がある方は見てみてください。

おわりに

正規表現まわりのミスはセキュリティホールにつながる感じがする、と思いました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0