Ruby On Rails, skillbuilder

Fix rails security headers

Firstly, we check the definitions below.

HeaderDescription
serverThis Server header seems to advertise the software being run on the server but you can remove or change this value.
permissions-policyPermissions Policy is a new header that allows a site to control which features and APIs can be used in the browser.
feature-policyFeature Policy has been renamed to Permissions Policy, see the details here.
set-cookieThere is no Cookie Prefix on this cookie.
strict-transport-securityHTTP Strict Transport Security is an excellent feature to support on your site and strengthens your implementation of TLS by getting the User Agent to enforce the use of HTTPS.
x-frame-optionsX-Frame-Options tells the browser whether you want to allow your site to be framed or not. By preventing a browser from framing your site you can defend against attacks like clickjacking.
x-content-type-optionsX-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. The only valid value for this header is “X-Content-Type-Options: nosniff”.
x-xss-protectionX-XSS-Protection sets the configuration for the XSS Auditor built into older browsers. The recommended value was “X-XSS-Protection: 1; mode=block” but you should now look at Content Security Policy instead.
referrer-policyReferrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites.
content-security-policyContent Security Policy is an effective measure to protect your site from XSS attacks. By whitelisting sources of approved content, you can prevent the browser from loading malicious assets. Analyse this policy in more detail. You can sign up for a free account on Report URI to collect reports about problems on your site.

I. Permissions-Policy

Permissions Policy is a new header that allows a site to control which features and APIs can be used in the browser.

As we can see above, the feature-policy has been changed to permissions-policy. I’m working on ruby 3.0.0 and rails 7.0.2 and encountered this issue. We easily find in config/initializers/permissions_policy.rb

Rails.application.config.permissions_policy do |f|<br>  f.camera      :none<br>  f.gyroscope   :none<br>  f.microphone  :none<br>  f.usb         :none<br>  f.fullscreen  :self<br>  f.payment     :self, "https://secure.example.com"<br>end

However, if we check it in https://securityheaders.com it still failed. It’s because rails set Feature-policy instead of permissions-policy. We fix it by adding before_action in ApplicationController.

def set_permission_policy
   response.headers["Permissions-Policy"] = response.headers["feature-policy"]
end

II. Strict-Transport-Security

HTTP Strict Transport Security is an excellent feature to support on your site and strengthens your implementation of TLS by getting the User Agent to enforce the use of HTTPS.

config.force_ssl = true

III. X-Frame-Options

X-Frame-Options tells the browser whether you want to allow your site to be framed or not. By preventing a browser from framing your site you can defend against attacks like clickjacking.

Use secure_headers gem and configure as below.

config.x_frame_options = "DENY"

IV. X-Content-Type-Options

X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. The only valid value for this header is “X-Content-Type-Options: nosniff”.

config.x_content_type_options = "nosniff"

V. Referrer-Policy

Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites.

config.referrer_policy = "strict-origin-when-cross-origin"

VI. Content-Security-Policy

Content Security Policy is an effective measure to protect your site from XSS attacks. By whitelisting sources of approved content, you can prevent the browser from loading malicious assets. Analyse this policy in more detail. You can sign up for a free account on Report URI to collect reports about problems on your site.

Set as default of secure_headers gem. Recommend to remove “unsafe-inline” which mean removing the script inside html. This is insecured maner.

config.csp = {
    # "meta" values. these will shape the header, but the values are not included in the header.
    preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
    disable_nonce_backwards_compatibility: true, # default: false. If false, `unsafe-inline` will be added automatically when using nonces. If true, it won't. See #403 for why you'd want this.

    # directive values: these values will directly translate into source directives
    default_src: %w('none'),
    base_uri: %w('self'),
    child_src: %w('self'), # if child-src isn't supported, the value for frame-src will be set.
    connect_src: %w(wss:),
    font_src: %w('self' data:),
    form_action: %w('self' github.com),
    frame_ancestors: %w('none'),
    img_src: %w(mycdn.com data:),
    manifest_src: %w('self'),
    media_src: %w(utoob.com),
    object_src: %w('self'),
    sandbox: true, # true and [] will set a maximally restrictive setting
    plugin_types: %w(application/x-shockwave-flash),
    script_src: %w('self'),
    script_src_elem: %w('self'),
    script_src_attr: %w('self'),
    style_src: %w('unsafe-inline'),
    style_src_elem: %w('unsafe-inline'),
    style_src_attr: %w('unsafe-inline'),
    worker_src: %w('self'),
    upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
    report_uri: %w(https://report-uri.io/example-csp)
  }

VII. CORS

Should control Origin and disable OPTIONS method if not using frontend framework.

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins /https?:\/\/.*\.youdomain\.com\.sg/
    resource '*', headers: :any, methods: [:get, :post, :patch, :put],
             expose: ['Access-Control-Allow-Origin']

  end
end

Bonus

I found an issue that I can’t access back link after clicking link in email. I navigated to login page but after logged in, it went to home page instead of back link in email. The reason is that cookie_store we set. If no mention about same_site, it’s default “Strict”.

SameSite=Lax: Allows cookies in top-level navigations but blocks them in third-party contexts, which is generally a secure default.

SameSite=Strict: Completely blocks cookies in any cross-site context, even for top-level navigations.

SameSite=None: Allows cookies in cross-site contexts but requires Secure to be set as well, meaning the site must use HTTPS.

We clarify the same_site as lax to allow this feature.

config.session_store :cookie_store, key: '_your_app_session', same_site: :lax
0