Ruby on Railsサイトで維持しており、httpsプロトコルを使用して相対URLへのリダイレクトを実行する方法について混乱しています。
たとえば、httpを使用して相対URLへのリダイレクトを正常に作成できます。
redirect_to "/some_directory/"
しかし、httpsプロトコルを使用してURLへのリダイレクトを作成する方法がわかりません。私は絶対URLを使用することによってのみそれを行うことができました、例えば:
redirect_to "https://mysite.com/some_directory/"
コードをきれいに保ちたいので、相対URLを使用するのは良い考えのようです。 Railsでこれを達成する方法を誰かが知っていますか?
ssl_requirement
であり、リンクまたはリダイレクトがhttpsを使用しているかどうかを気にしません。 ssl_requirementを使用して、SSLを必要とするアクション、SSLを実行できるアクション、SSLを使用しないために必要なアクションを宣言します。
Railsアプリの外のどこかにリダイレクトしている場合は、Ollyが提案するようにプロトコルを指定すると機能します。
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
アプリケーション全体を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'] }
この回答は、元の質問にいくぶん正接しますが、他の人が私と同じような状況でここに到着する場合に備えて、私はそれを記録します。
すべてのリクエストのオリジンが暗号化されていなくても(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
コントローラーで生成された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で機能します。以前のバージョンまたは将来のバージョンについて正確にはわかりません。
Rails 4では、force_ssl_redirect
before_actionは、単一のコントローラーにsslを適用します。この方法を使用すると、Cookieが安全であるとマークされず、 [〜#〜] hsts [〜#〜] が使用されないことに注意してください。