rails config.force_ssl についてメモ

railsdoc.com

config.force_ssl = true

にすると、以下のようにActionDispatch::SSLというmiddlewareが有効になる

if config.force_ssl
  middleware.use ::ActionDispatch::SSL, **config.ssl_options,
    ssl_default_redirect_status: config.action_dispatch.ssl_default_redirect_status
end

やってることは以下

rails/ssl.rb at v7.0.2.2 · rails/rails · GitHub

request.ssl?がfalseの場合、httpsにリダイレクトする

if request.ssl?
   ...
else
   return redirect_to_https request unless @exclude.call(request)
   ...
end

Cookieにsecure 属性をつける

def flag_cookies_as_secure!(headers)
  if cookies = headers["Set-Cookie"]
    cookies = cookies.split("\n")

    headers["Set-Cookie"] = cookies.map { |cookie|
      if !/;\s*secure\s*(;|$)/i.match?(cookie)
        "#{cookie}; secure"
      else
        cookie
      end
    }.join("\n")
  end
end

HTTP Strict Transport Security (HSTS) headerを追加する。

# https://tools.ietf.org/html/rfc6797#section-6.1
def build_hsts_header(hsts)
  value = +"max-age=#{hsts[:expires].to_i}"
  value << "; includeSubDomains" if hsts[:subdomains]
  value << "; preload" if hsts[:preload]
  value
end

request.ssl? の中身はというと、Rack::Request::Helpers にあるっぽい。 rack/request.rb at v2.2.2 · rack/rack · GitHub

こんな感じで、headerとか、X-Forwarded-Forにも対応してる。

def ssl?
   scheme == 'https' || scheme == 'wss'
end

def scheme
    if get_header(HTTPS) == 'on'
        'https'
    elsif get_header(HTTP_X_FORWARDED_SSL) == 'on'
        'https'
    elsif forwarded_scheme
        forwarded_scheme
    else
        get_header(RACK_URL_SCHEME)
    end
end

def forwarded_scheme
    allowed_scheme(get_header(HTTP_X_FORWARDED_SCHEME)) ||
    allowed_scheme(extract_proto_header(get_header(HTTP_X_FORWARDED_PROTO)))
end

なので、AWSでよくある、HTTPS -> ALB -> HTTP -> EC2 といった通信の場合は、内部ではHTTP通信でもRedirectされない。