以下の記事の続きです。
Rails: config.force_ssl = true によるHSTSの動作をローカル環境とChromeで試してみた
参考: Rails API ActionDispatch::SSL
⚓Rails 5と6のHSTS設定方法
Rails 5以降では、config/environments/production.rbで以下の設定をコメント解除すると、production環境で強制的にHTTPS通信を試みるようになり、同時にHSTS「も」有効になります。
config.force_ssl = true
- ドキュメント: Rails アプリケーションを設定する - Railsガイド
production環境のRailsサーバーでHSTS(HTTP Strict Transport Security)が有効になると、サーバーからのHTTPレスポンスに以下のようなStrict-Transport-Security
ヘッダーが追加されます。
Strict-Transport-Security: includeSubDomains
ブラウザはStrict-Transport-Security
ヘッダーを受け取るとそのサーバーのドメインを記憶し、以後そのドメインにアクセスするときは、たとえhttp://
を指定した場合でもHTTPS通信にリダイレクトを試みます。記憶を解除する方法については前回記事の末尾をご覧ください。
⚓デフォルトのHSTS設定
Railsのssl_options
に何も指定しない場合のデフォルトのHSTS設定は以下のようになります(railties/lib/rails/application/configuration.rb#L94)。デフォルトではincludeSubDomains
が有効になりますので、サブドメインもHSTSの対象になります。
# railties/lib/rails/application/configuration.rb#L94
self.ssl_options = { hsts: { subdomains: true } }
includeSubDomains
を明示的に無効にするには、config/environments/production.rbのconfig.ssl_options
でsubdomains: false
を指定します。
config.ssl_options = { hsts: { subdomains: false } }
production環境でRailsのforce_ssl = true
を有効にする前には、HSTSの設定が本番にとって適切かどうかを確認しておきましょう。シチュエーションによってはデフォルトのHSTS設定でも問題が起きるかもしれません。
参考: ネイキッドドメイン+HTTPSで運用するRailsアプリを5.1にアップグレードしたら、サブドメインも強制的にHTTPSになってしまった話 - Qiita
⚓HSTS有効期限の設定追加
config/environments/production.rbのconfig.ssl_options
に{ expires: 10.days }
などと追加することで、HSTSの有効期限をmax-age
で指定できます↓。max-age
の単位は秒ですが、Railsでは10.days
などと楽に指定できます。
config.ssl_options = { hsts: { expires: 10.days } }
指定の期限を過ぎると、http://
でアクセスしたときに元のようにHTTP通信を試みます。
Strict-Transport-Security: max-age=86400
⚓HSTSをオフにする
参考: Strict-Transport-Security - HTTP | MDN
試したわけではありませんが、MDNによると、HTTPS通信時にmax-age=0
を指定するとStrict-Transport-Security
ヘッダーを失効させることができ、ブラウザが再びHTTP通信を許すようになるそうです。
RailsでHSTSをオフにするには、config.ssl_options
で単にhsts: false
と指定するか、hsts: { expires: 0 }
を指定します。
config.ssl_options = { hsts: false }
# または
config.ssl_options = { hsts: { expires: 0 } }
⚓preload
設定
production環境でのHSTS preload設定は、非暗号化通信を排除しなければならないような特殊な案件で使うことがあります。Railsではデフォルトでpreload: false
です。
preloadしないHSTSでは、暗号化されていないHTTPでサイトにアクセスするとHTTPSへの301リダイレクトが発生する可能性が残りますが、hstspreload.orgのpreloadリストに登録するとブラウザは最初からHTTPSのみで通信するようになり、HTTPからHTTPSへの301リダイレクトを排除できるようになります。
ただしhstspreload.orgのpreloadリスト登録は後からの取り消しが難しいので慎重に行いましょう。
hstspreload.orgのHSTS preloadリストに登録するには、少なくともサイト全体をもれなくHTTPSのみでアクセス可能にしておく必要があります(暗号化されていないHTTPアクセスのページが残っていると、そのページにアクセスできなくなってしまいます)。
hstspreload.orgへのドメイン名登録ではサブドメインも対象に含まれる(正確にはincludeSubDomains
指定を省略できない)ので、暗号化されていないHTTPページがサブドメインにあると、やはりアクセスできなくなってしまいます。
失敗に備えて、最初はmax-age
を1日(86400)程度にして試すのが無難なのかなと思います。なお現在はmax-age
を少なくとも1年間にしなければならないとhstspreload.orgで警告されます↓。
The max-age must be at least 31536000 seconds (≈ 1 year), but the header currently only has max-age=2592000.
プリロードについてはまだ怖くて試せていないので、Railsでの設定方法のみをメモします。
config/environments/production.rbのconfig.ssl_options
でpreload: true
を指定すると、以後アクセスするブラウザは、プリロードリストに従って強制的に最初からHTTPSでそのドメイン(とサブドメイン)にアクセスするようになり、設定は1年間持続します。
config.ssl_options = { hsts: { max-age: 31536000, subdomains: true, preload: true } }
参考: 3分で出来るHSTSプリロードの設定方法 – 常時SSL化後に必ず行うべき設定
参考: HTTP Strict Transport Security - Qiita