Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 5と6のHSTS設定方法

以下の記事の続きです。

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

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_optionssubdomains: 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_optionspreload: trueを指定すると、以後アクセスするブラウザは、プリロードリストに従って強制的に最初からHTTPSでそのドメイン(とサブドメイン)にアクセスするようになり、設定は1年間持続します。

config.ssl_options = { hsts: { max-age: 31536000, subdomains: true, preload: true } }

参考: 3分で出来るHSTSプリロードの設定方法 – 常時SSL化後に必ず行うべき設定
参考: HTTP Strict Transport Security - Qiita


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。