kemal-shield

This is a shard that adds an extra layer of protection to your Kemal app. This is done by setting various HTTP headers.

This shard is inspired by Helmet.

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      kemal-shield:
        github: henrikac/kemal-shield
  2. Run shards install

Usage

Basic usage

require "kemal"
require "kemal-shield"

Kemal::Shield.activate # => adds handlers with their default settings

get "/" do
  "Home"
end

Kemal.run

Managing handlers

Add handlers

The handlers can also be added individually as you would add any other handler. The recommended way of adding handlers is to use Kemal::Shield.add_handler instead of Kemal's built-in add_handler. The reason for using Kemal::Shield.add_handler over Kemal's built-in add_handler is that Kemal::Shield.add_handler keeps track of all Kemal::Shield::Handler. It also makes sure that no dublicate Kemal::Shield::Handler is being added.

Kemal::Shield.add_handler Kemal::Shield::XPoweredBy.new
Kemal::Shield.add_handler Kemal::Shield::XFrameOptions.new("DENY")

A Kemal::Shield::DublicateHandlerError is raised if a dublicate handler is added.

Remove handlers

There are two ways of removing a Kemal::Shield::Handler.

  1. Kemal::Shield.remove_handler if you just need to remove a single handler
  2. Kemal::Shield.deactivate if you want to remove all Kemal::Shield::Handler.
Kemal::Shield.remove_handler Kemal::Shield::ExpectCT

Custom handler

Creating a new handler works just as creating a regular Kemal handler. The only difference is that the new handlers should inherit from Kemal::Shield::Handler instead of Kemal::Handler.

class CustomHandler < Kemal::Shield::Handler
  def call(context)
    # code ...
    call_next context
  end
end

This makes it possible to add handlers using Kemal::Shield.add_handler and/or remove handlers using Kemal::Shield.remove_handler or Kemal::Shield.deactivate.

Configuration

The different headers can be configured in the same way as Kemal:

Kemal::Shield.config do |config|
  config.csp_on = true
  config.hide_powered_by = true
  config.no_sniff = true
  config.referrer_policy = ["no-referrer"]
  config.x_xss_protection = false
end

or

Kemal::Shield.config.hide_powered_by = true

Configuration should be done before calling Kemal::Shield.activate. This is to make sure that the handlers will use the custom configurations.

Kemal::Shield.config.corp = "cross-origin" # => Good: This will be used when calling .activate

Kemal::Shield.activate

Kemal::Shield.config.corp = "same-site" # => Bad: Handlers has already been initialized

| Option | Description | Default | |---|---|---| | csp_on | Set Content-Security-Policy header | true | | csp_defaults | Add CSP default directives | true | | csp_directives | CSP directives | DEFAULT_DIRECTIVES | | csp_report_only | Set Content-Security-Policy-Report-Only header | false | | coep_on | Set Cross-Origin-Embedder-Policy header | true | | coop_on | Set Cross-Origin-Opener-Policy header | true | | coop | Cross-Origin-Opener-Policy policy | "same-origin" | | corp_on | Set Cross-Origin-Resource-Policy header | true | | corp | Cross-Origin-Resource-Policy policy | "same-origin" | | expect_ct | Set Expect-CT header | true | | expect_ct_max_age | Seconds the user agent should regard the host of the received message as a known Expect-CT host | 0 | | expect_ct_enforce | Whether the user agent should enforce compliance with the Certificate Transparency policy | false | | expect_ct_report_uri | The URI where the user agent should report Expect-CT failures | "" | | hide_powered_by | Whether to remove the X-Powered-By header | true | | no_sniff | Set X-Content-Type-Options header | true | | oac | Set Origin-Agent-Cluster header | true | | referrer_on | Set Referrer-Policy header | true | | referrer_policy | The Referrer-Policy policy | ["no-referrer"] | | sts_on | Set Strict-Transport-Security | true | | sts_max_age | Seconds that the browser should remember that a site is only to be accessed using HTTPS | 15_552_000 | | sts_include_sub | Add rule to subdomains | true | | sts_preload | Preloading STS | false | | x_dns_prefetch_control_on | Set X-DNS-Prefetch-Control header | true | | x_dns_prefetch_control | Enable DNS prefetching | false | | x_download_options | Set X-Download-Options header | true | | x_frame_options_on | Set X-Frame-Options | true | | x_frame_options | X-Frame-Options directive | "SAMEORIGIN" | | x_permitted_cross_domain_policies_on | Set X-Permitted-Cross-Domain-Policies header | true | | x_permitted_cross_domain_policies | X-Permitted-Cross-Domain-Policies directive | none | | x_xss_protection | Enable X-XSS-Protection header | false |

ContentSecurityPolicy::DEFAULT_DIRECTIVES:

default-src 'self';
base-uri 'self';
block-all-mixed-content;
font-src 'self' https: data:;
frame-ancestors 'self';
img-src 'self' data:;
object-src 'none';
script-src 'self';
script-src-attr 'none';
style-src 'self' https: 'unsafe-inline';
upgrade-insecure-requests;

Handlers

Contributing

  1. Fork it (https://github.com/henrikac/kemal-shield/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors