{"id":15713727,"url":"https://github.com/henrikac/kemal-shield","last_synced_at":"2025-05-12T22:54:49.176Z","repository":{"id":140270941,"uuid":"382637217","full_name":"henrikac/kemal-shield","owner":"henrikac","description":"A shard that adds an extra layer of protection to Kemal apps by setting various HTTP headers.","archived":false,"fork":false,"pushed_at":"2021-07-06T16:11:02.000Z","size":55,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-12T22:54:42.529Z","etag":null,"topics":["crystal","crystal-lang","crystal-language"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/henrikac.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-03T14:36:30.000Z","updated_at":"2023-03-10T12:09:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"8573b227-ecfe-4de0-ac50-2aff861dda52","html_url":"https://github.com/henrikac/kemal-shield","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikac%2Fkemal-shield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikac%2Fkemal-shield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikac%2Fkemal-shield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henrikac%2Fkemal-shield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henrikac","download_url":"https://codeload.github.com/henrikac/kemal-shield/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253837389,"owners_count":21971981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crystal","crystal-lang","crystal-language"],"created_at":"2024-10-03T21:33:07.091Z","updated_at":"2025-05-12T22:54:49.156Z","avatar_url":"https://github.com/henrikac.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kemal-shield\n\nThis is a shard that adds an extra layer of protection to your [Kemal](https://github.com/kemalcr/kemal) app. This is done by setting various HTTP headers.  \n\nThis shard is inspired by [Helmet](https://github.com/helmetjs/helmet).\n\n## Installation\n\n1. Add the dependency to your `shard.yml`:\n\n   ```yaml\n   dependencies:\n     kemal-shield:\n       github: henrikac/kemal-shield\n   ```\n\n2. Run `shards install`\n\n## Usage\n\n#### Basic usage\n```crystal\nrequire \"kemal\"\nrequire \"kemal-shield\"\n\nKemal::Shield.activate # =\u003e adds handlers with their default settings\n\nget \"/\" do\n  \"Home\"\nend\n\nKemal.run\n```\n\n#### Managing handlers\n##### Add handlers\nThe handlers can also be added individually as you would add any other handler.\nThe recommended way of adding handlers is to use `Kemal::Shield.add_handler` instead of Kemal's built-in `add_handler`.\nThe 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`.\nIt also makes sure that no dublicate `Kemal::Shield::Handler` is being added.\n\n```crystal\nKemal::Shield.add_handler Kemal::Shield::XPoweredBy.new\nKemal::Shield.add_handler Kemal::Shield::XFrameOptions.new(\"DENY\")\n```\n\nA `Kemal::Shield::DublicateHandlerError` is raised if a dublicate handler is added.\n\n##### Remove handlers\nThere are two ways of removing a `Kemal::Shield::Handler`.  \n\n1. `Kemal::Shield.remove_handler` if you just need to remove a single handler\n2. `Kemal::Shield.deactivate` if you want to remove all `Kemal::Shield::Handler`.\n\n```crystal\nKemal::Shield.remove_handler Kemal::Shield::ExpectCT\n```\n\n#### Custom handler\nCreating a new handler works just as creating a regular Kemal handler.\nThe only difference is that the new handlers should inherit from `Kemal::Shield::Handler` instead of `Kemal::Handler`.\n\n```crystal\nclass CustomHandler \u003c Kemal::Shield::Handler\n  def call(context)\n    # code ...\n    call_next context\n  end\nend\n```\n\nThis makes it possible to add handlers using `Kemal::Shield.add_handler` and/or remove handlers using `Kemal::Shield.remove_handler` or `Kemal::Shield.deactivate`.\n\n#### Configuration\nThe different headers can be configured in the same way as Kemal:\n\n```crystal\nKemal::Shield.config do |config|\n  config.csp_on = true\n  config.hide_powered_by = true\n  config.no_sniff = true\n  config.referrer_policy = [\"no-referrer\"]\n  config.x_xss_protection = false\nend\n```\nor\n```crystal\nKemal::Shield.config.hide_powered_by = true\n```\n\nConfiguration should be done before calling `Kemal::Shield.activate`.\nThis is to make sure that the handlers will use the custom configurations.\n\n```crystal\nKemal::Shield.config.corp = \"cross-origin\" # =\u003e Good: This will be used when calling .activate\n\nKemal::Shield.activate\n\nKemal::Shield.config.corp = \"same-site\" # =\u003e Bad: Handlers has already been initialized\n```\n\n| Option | Description | Default |\n|---|---|---|\n| csp_on | Set Content-Security-Policy header | `true` |\n| csp_defaults | Add CSP default directives | `true` |\n| csp_directives | CSP directives | `DEFAULT_DIRECTIVES` |\n| csp_report_only | Set Content-Security-Policy-Report-Only header | `false` |\n| coep_on | Set Cross-Origin-Embedder-Policy header | `true` |\n| coop_on | Set Cross-Origin-Opener-Policy header | `true` |\n| coop | Cross-Origin-Opener-Policy policy | `\"same-origin\"` |\n| corp_on | Set Cross-Origin-Resource-Policy header | `true` |\n| corp | Cross-Origin-Resource-Policy policy | `\"same-origin\"` |\n| expect_ct | Set Expect-CT header | `true` |\n| expect_ct_max_age | Seconds the user agent should regard the host of the received message as a known Expect-CT host | `0` |\n| expect_ct_enforce | Whether the user agent should enforce compliance with the Certificate Transparency policy | `false` |\n| expect_ct_report_uri | The URI where the user agent should report Expect-CT failures | `\"\"` |\n| hide_powered_by | Whether to remove the X-Powered-By header | `true` |\n| no_sniff | Set X-Content-Type-Options header  | `true` |\n| oac | Set Origin-Agent-Cluster header | `true` |\n| referrer_on | Set Referrer-Policy header | `true` |\n| referrer_policy | The Referrer-Policy policy | `[\"no-referrer\"]` |\n| sts_on | Set Strict-Transport-Security | `true` |\n| sts_max_age | Seconds that the browser should remember that a site is only to be accessed using HTTPS | `15_552_000` |\n| sts_include_sub | Add rule to subdomains | `true` |\n| sts_preload | [Preloading STS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#preloading_strict_transport_security) | `false` |\n| x_dns_prefetch_control_on | Set X-DNS-Prefetch-Control header | `true` |\n| x_dns_prefetch_control | Enable DNS prefetching | `false` |\n| x_download_options | Set X-Download-Options header | `true` |\n| x_frame_options_on | Set X-Frame-Options | `true` |\n| x_frame_options | X-Frame-Options directive | `\"SAMEORIGIN\"` |\n| x_permitted_cross_domain_policies_on | Set X-Permitted-Cross-Domain-Policies header | `true` |\n| x_permitted_cross_domain_policies | X-Permitted-Cross-Domain-Policies directive | `none` |\n| x_xss_protection | Enable X-XSS-Protection header | `false` |\n\n\n`ContentSecurityPolicy::DEFAULT_DIRECTIVES`:\n```\ndefault-src 'self';\nbase-uri 'self';\nblock-all-mixed-content;\nfont-src 'self' https: data:;\nframe-ancestors 'self';\nimg-src 'self' data:;\nobject-src 'none';\nscript-src 'self';\nscript-src-attr 'none';\nstyle-src 'self' https: 'unsafe-inline';\nupgrade-insecure-requests;\n```\n\n\n#### Handlers\n+ `ContentSecurityPolicy`\n+ `CrossOriginEmbedderPolicy`\n+ `CrossOriginOpenerPolicy`\n+ `CrossOriginResourcePolicy`\n+ `ExpectCT`\n+ `OriginAgentCluster`\n+ `ReferrerPolicy`\n+ `StrictTransportSecurity`\n+ `XContentTypeOptions`\n+ `XDNSPrefetchControl`\n+ `XDownloadOptions`\n+ `XFrameOptions`\n+ `XPermittedCrossDomainPolicies`\n+ `XPoweredBy`\n+ `XXSSProtection`\n\n## Contributing\n\n1. Fork it (\u003chttps://github.com/henrikac/kemal-shield/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Contributors\n\n- [Henrik Christensen](https://github.com/henrikac) - creator and maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrikac%2Fkemal-shield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenrikac%2Fkemal-shield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenrikac%2Fkemal-shield/lists"}