web-dev-qa-db-ja.com

Rails httpsでリダイレクト

Ruby on Railsサイトで維持しており、httpsプロトコルを使用して相対URLへのリダイレクトを実行する方法について混乱しています。

たとえば、httpを使用して相対URLへのリダイレクトを正常に作成できます。

redirect_to "/some_directory/"

しかし、httpsプロトコルを使用してURLへのリダイレクトを作成する方法がわかりません。私は絶対URLを使用することによってのみそれを行うことができました、例えば:

redirect_to "https://mysite.com/some_directory/"

コードをきれいに保ちたいので、相対URLを使用するのは良い考えのようです。 Railsでこれを達成する方法を誰かが知っていますか?

28
Brian D'Astous

ssl_requirement であり、リンクまたはリダイレクトがhttpsを使用しているかどうかを気にしません。 ssl_requirementを使用して、SSLを必要とするアクション、SSLを実行できるアクション、SSLを使用しないために必要なアクションを宣言します。

Railsアプリの外のどこかにリダイレクトしている場合は、Ollyが提案するようにプロトコルを指定すると機能します。

11
Andy Gaskell

ActionController::Base#redirect_toメソッドはオプションハッシュを受け取ります。そのパラメータの1つは:protocolで、これを呼び出すことができます。

redirect_to :protocol => 'https://', 
            :controller => 'some_controller', 
            :action => 'index'

オプションの詳細については、 #redirect_to および #url_for の定義を参照してください。


または、特にすべてのコントローラーアクションにSSLを使用する場合は、before_filterを使用してより宣言的なアプローチをとることができます。 ApplicationControllerでは、次のメソッドを定義できます。

def redirect_to_https
    redirect_to :protocol => "https://" unless (request.ssl? || request.local?)
end

次に、SSLを必要とするアクションを持つコントローラーにフィルターを追加できます。

class YourController
    before_filter :redirect_to_https, :only => ["index", "show"]
end

または、アプリ全体でSSLが必要な場合は、ApplicationControllerでフィルターを宣言します。

class ApplicationController
    before_filter :redirect_to_https
end
37
Olly

アプリケーション全体をhttps経由で提供したい場合は、Rails 4.0以来、最良の方法ですこれはforce_ssl構成ファイルで次のように記述します。

# config/environments/production.rb
Rails.application.configure do
  # [..]

  # Force all access to the app over SSL, use Strict-Transport-Security,
  # and use secure cookies.
  config.force_ssl = true
end

デフォルトでは、このオプションはすでにconfig/environments/production.rbは、新しく生成されたアプリで使用されますが、コメント化されています。

コメントが言うように、これはhttpsにリダイレクトするだけでなく、Strict-Transport-Securityヘッダー( [〜#〜] hsts [〜#〜] )で、すべてのCookieにセキュアフラグが設定されていることを確認します。どちらの方法でも、重大な欠点なしにアプリケーションのセキュリティが向上します。それは使用しています - ActionDispatch:SSL

HSTSの有効期限の設定はデフォルトで1年に設定されており、サブドメインは含まれていません。これは、ほとんどのアプリケーションでおそらく問題ありません。これはhstsオプションで設定できます:

config.hsts = {
  expires: 1.month.to_i,
  subdomains: false,
}

Rails 3(> = 3.1)を実行している場合、またはアプリケーション全体にhttpsを使用したくない場合は、- force_ssl コントローラのメソッド:

class SecureController < ApplicationController
  force_ssl
end

それで全部です。コントローラごと、またはApplicationControllerで設定できます。使い慣れたifまたはunlessオプションを使用して、条件付きでhttpsを強制できます。例えば:

# Only when we're not in development or tests
force_ssl unless: -> { Rails.env.in? ['development', 'test'] }
30
Martin Tournoij

この回答は、元の質問にいくぶん正接しますが、他の人が私と同じような状況でここに到着する場合に備えて、私はそれを記録します。

すべてのリクエストのオリジンが暗号化されていなくても(https)、RailsにURLヘルパーなどでhttpプロトコルを使用する必要がある状況がありました。

現在、通常この状況では(Railsがリバースプロキシまたはロードバランサなどの背後にある場合は正常です)、x-forwarded-protoヘッダーはリバースプロキシなどによって設定されるため、リクエストがプロキシとRailsの間で暗号化されていません(おそらく本番環境ではお勧めできません)Railsはすべてがhttpsにあると考えています。

Ngrok tlsトンネルの後ろを走る必要がありました。 ngrokに、指定したletsencrypt証明書でtlsを終了させたいと思っていました。ただし、その場合、ngrokはx-forwarded-protoの設定など、ヘッダーをカスタマイズする機能を提供しません(この機能は将来的に計画されています)。

解決策は非常にシンプルであることがわかりました。Railsは、Originのプロトコルやx-forwarded-protoが直接設定されているかどうかに依存せず、Rack env var rack.url_schemeに依存します。だから私はこのラックミドルウェアを開発に追加する必要がありました:

class ForceUrlScheme
  def initialize(app)
    @app = app
  end

  def call(env)
    env['rack.url_scheme'] = 'https'
    @app.call(env)
  end
end
3

コントローラーで生成されたURLのプロトコルをグローバルに制御する場合は、アプリケーションコントローラーでurl_optionsメソッドをオーバーライドできます。 Rails envに応じて、生成されたURLのプロトコルを次のように強制できます。

 def url_options
    super
    @_url_options.dup.tap do |options|
      options[:protocol] = Rails.env.production? ? "https://" : "http://"
      options.freeze
    end
  end

この例は、Rails 3.2.1で機能します。以前のバージョンまたは将来のバージョンについて正確にはわかりません。

2
Shamu

Rails 4では、force_ssl_redirect before_actionは、単一のコントローラーにsslを適用します。この方法を使用すると、Cookieが安全であるとマークされず、 [〜#〜] hsts [〜#〜] が使用されないことに注意してください。

2
Samuel