{"id":15037749,"url":"https://github.com/brokenhandsio/vaporsecurityheaders","last_synced_at":"2025-04-04T13:12:52.490Z","repository":{"id":17533525,"uuid":"81859842","full_name":"brokenhandsio/VaporSecurityHeaders","owner":"brokenhandsio","description":"Harden Your Security Headers For Vapor","archived":false,"fork":false,"pushed_at":"2024-11-03T20:39:16.000Z","size":203,"stargazers_count":149,"open_issues_count":0,"forks_count":14,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-04T13:12:46.639Z","etag":null,"topics":["brokenhands","security","server-side-swift","swift","swift-3","swift-framework","vapor","vapor-provider"],"latest_commit_sha":null,"homepage":null,"language":"Swift","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/brokenhandsio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2017-02-13T18:58:15.000Z","updated_at":"2025-02-14T17:25:54.000Z","dependencies_parsed_at":"2025-01-18T19:52:28.516Z","dependency_job_id":null,"html_url":"https://github.com/brokenhandsio/VaporSecurityHeaders","commit_stats":{"total_commits":163,"total_committers":13,"mean_commits":"12.538461538461538","dds":"0.25153374233128833","last_synced_commit":"732edf8579a7324a1b26e001a5007123047ac992"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brokenhandsio%2FVaporSecurityHeaders","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brokenhandsio%2FVaporSecurityHeaders/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brokenhandsio%2FVaporSecurityHeaders/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brokenhandsio%2FVaporSecurityHeaders/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brokenhandsio","download_url":"https://codeload.github.com/brokenhandsio/VaporSecurityHeaders/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182401,"owners_count":20897381,"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":["brokenhands","security","server-side-swift","swift","swift-3","swift-framework","vapor","vapor-provider"],"created_at":"2024-09-24T20:35:32.457Z","updated_at":"2025-04-04T13:12:52.465Z","avatar_url":"https://github.com/brokenhandsio.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/9938337/29741110-2e0ae9ca-8a5e-11e7-8fbf-58b256d4dd57.png\" alt=\"Vapor Security Headers\"\u003e\n    \u003cbr\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://swift.org\"\u003e\n        \u003cimg src=\"http://img.shields.io/badge/Swift-5.2-brightgreen.svg\" alt=\"Language\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/brokenhandsio/VaporSecurityHeaders/actions\"\u003e\n         \u003cimg src=\"https://github.com/brokenhandsio/VaporSecurityHeaders/workflows/CI/badge.svg?branch=master\" alt=\"Build Status\"\u003e\n    \u003ca href=\"https://codecov.io/gh/brokenhandsio/VaporSecurityHeaders\"\u003e\n        \u003cimg src=\"https://codecov.io/gh/brokenhandsio/VaporSecurityHeaders/branch/master/graph/badge.svg\" alt=\"Code Coverage\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://raw.githubusercontent.com/brokenhandsio/VaporSecurityHeaders/master/LICENSE\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT License\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nA Middleware library for adding security headers to your Vapor application.\n\n# Features\n\nEasily add headers to all your responses for improving the security of your site for you and your users. Currently supports:\n\n* Content-Security-Policy\n* Content-Security-Policy-Report-Only\n* X-XSS-Protection\n* X-Frame-Options\n* X-Content-Type-Options\n* Strict-Transport-Security (HSTS)\n* Redirect HTTP to HTTPS\n* Server\n* Referrer Policy\n\nThese headers will *help* prevent cross-site scripting attacks, SSL downgrade attacks, content injection attacks, click-jacking etc. They will not help for any attacks directly against your server, but they will help your users and help secure sensitive information (CSRF tokens). Please note that this library does not guarantee anything and nothing is ever completely secure.\n\n# Usage\n\n## Add the package\n\nAdd the package as a dependency in your `Package.swift` manifest:\n\n```swift\ndependencies: [\n    ...,\n    .package(url: \"https://github.com/brokenhandsio/VaporSecurityHeaders.git\", from: \"3.0.0\")\n]\n```\n\nThen add the dependency to your target:\n\n```swift\n.target(name: \"App\",\n        dependencies: [\n                // ...\n                \"VaporSecurityHeaders\"]),\n```\n\n## Configuration\n\nTo use Vapor Security Headers, you need to add the middleware to your `Application`'s `Middlewares`. Vapor Security Headers makes this easy to do with a `build` function on the factory. **Note:** if you want security headers added to error reponses (recommended), you need to initialise the `Middlewares` from fresh and add the middleware in _after_ the `SecuriyHeaders`. In `configure.swift` add:\n\n```swift\nlet securityHeadersFactory = SecurityHeadersFactory()\n\napplication.middleware = Middlewares()\napplication.middleware.use(securityHeadersFactory.build())\napplication.middleware.use(ErrorMiddleware.default(environment: application.environment))\n// Add other middlewares...\n```\n\nThe default factory will add default values to your site for Content-Security-Policy, X-XSS-Protection, X-Frame-Options and X-Content-Type-Options.\n\n```HTTP\nx-content-type-options: nosniff\ncontent-security-policy: default-src 'self'\nx-frame-options: DENY\nx-xss-protection: 0\n```\n\n***Note:*** You should ensure you set the security headers as the first middleware in your `Middlewares` (i.e., the first middleware to be applied to responses) to make sure the headers get added to all responses.\n\nIf you want to add your own values, it is easy to do using the factory. For instance, to add a content security policy configuration, just do:\n\n```swift\nlet cspValue = \"default-src 'none'; script-src https://static.brokenhands.io;\"\n\nlet cspConfig = ContentSecurityPolicyConfiguration(value: cspValue)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(contentSecurityPolicy: cspConfig)\napplication.middleware.use(securityHeadersFactory.build())\n```\n\n```HTTP\nx-content-type-options: nosniff\ncontent-security-policy: default-src 'none'; script-src https://static.brokenhands.io;\nx-frame-options: DENY\nx-xss-protection: 0\n```\n\nEach different header has its own configuration and options, details of which can be found below.\n\nYou can test your site by visiting the awesome [Security Headers](https://securityheaders.io) (no affiliation) website.\n\n## API Headers\n\nIf you are running an API you can choose a default configuration for that by creating it with:\n\n```swift\nlet securityHeaders = SecurityHeadersFactory.api()\napplication.middleware.use(securityHeaders.build())\n```\n\n```http\nx-content-type-options: nosniff\ncontent-security-policy: default-src 'none'\nx-frame-options: DENY\nx-xss-protection: 0\n```\n\n# Server Configuration\n\n## Vapor\n\nIf you are running Vapor on it's own (i.e. not as a CGI application or behind a reverse proxy) then you do not need to do anything more to get it running!\n\n## Nginx, Apache and 3rd Party Services\n\nBoth web servers should pass on the response headers from Vapor without issue when running as a reverse proxy. Some servers and providers (such as Heroku) will inject their own headers or block certain headers (such as HSTS to stop you locking out their whole site). You will need to check with your provider to see what is enabled and allowed.\n\n# Security Header Information\n\n## Content-Security-Policy\n\nContent Security Policy is one of the most effective tools for protecting against cross-site scripting attacks. In essence it is a way of whitelisting sources for content so that you only load from known and trusted sources. For more information about CSP, read Scott Helme's [awesome blog post](https://scotthelme.co.uk/content-security-policy-an-introduction/) which tells you how to configure it and what to use.\n\nThe Vapor Security Headers package will set a default CSP of `default-src: 'self'`, which means that you can load images, scripts, fonts, CSS etc **only** from your domain. It also means that you cannot have any inline Javascript or CSS, which is one of the most effective measures you can take in protecting your site, and will wipe out a large proportion of content-injection attacks.\n\nThe API default CSP is `default-src: 'none'` as an API should only return data and never be loading scripts or images to display!\n\nYou can build a CSP header (`ContentSecurityPolicy`) with the following directives: \n\n- baseUri(sources)\n- blockAllMixedContent()\n- connectSrc(sources)\n- defaultSrc(sources)\n- fontSrc(sources)\n- formAction(sources)\n- frameAncestors(sources)\n- frameSrc(sources)\n- imgSrc(sources)\n- manifestSrc(sources)\n- mediaSrc(sources)\n- objectSrc(sources)\n- pluginTypes(types)\n- reportTo(json_object)\n- reportUri(uri)\n- requireSriFor(values)\n- sandbox(values)\n- scriptSrc(sources)\n- styleSrc(sources)\n- upgradeInsecureRequests()\n- workerSrc(sources)\n\n*Example:*\n\n```swift\nlet cspConfig = ContentSecurityPolicy()\n        .scriptSrc(sources: \"https://static.brokenhands.io\")\n        .styleSrc(sources: \"https://static.brokenhands.io\")\n        .imgSrc(sources: \"https://static.brokenhands.io\")\n```\n\n```http\nContent-Security-Policy: script-src https://static.brokenhands.io; style-src https://static.brokenhands.io; img-src https://static.brokenhands.io\n```\n\nYou can set a custom header with ContentSecurityPolicy().set(value) or ContentSecurityPolicyConfiguration(value).\n\n**ContentSecurityPolicy().set(value)**\n\n```swift\nlet cspBuilder = ContentSecurityPolicy().set(value: \"default-src: 'none'\")\n\nlet cspConfig = ContentSecurityPolicyConfiguration(value: cspBuilder)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(contentSecurityPolicy: cspConfig)\n```\n\n**ContentSecurityPolicyConfiguration(value)**\n\n```swift\nlet cspConfig = ContentSecurityPolicyConfiguration(value: \"default-src 'none'\")\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(contentSecurityPolicy: cspConfig)\n```\n\n```http\nContent-Security-Policy: default-src: 'none'\n```\n\nThe following CSP keywords (`CSPKeywords`) are also available to you: \n\n* CSPKeywords.all = *\n* CSPKeywords.none = 'none'\n* CSPKeywords.\\`self\\` = 'self'\n* CSPKeywords.strictDynamic = 'strict-dynamic'\n* CSPKeywords.unsafeEval = 'unsafe-eval'\n* CSPKeywords.unsafeHashedAttributes = 'unsafe-hashed-attributes'\n* CSPKeywords.unsafeInline = 'unsafe-inline'\n\n*Example:*\n\n``` swift\nCSPKeywords.`self` // “‘self’”\nContentSecurityPolicy().defaultSrc(sources: CSPKeywords.`self`)\n```\n\n```http\nContent-Security-Policy: default-src 'self'\n```\n\nYou can also utilize the `Report-To` directive:\n\n```swift\nlet reportToEndpoint = CSPReportToEndpoint(url: \"https://csp-report.brokenhands.io/csp-reports\")\n\nlet reportToValue = CSPReportTo(group: \"vapor-csp\", max_age: 10886400, endpoints: [reportToEndpoint], include_subdomains: true)\n\nlet cspValue = ContentSecurityPolicy()\n    .defaultSrc(sources: CSPKeywords.none)\n    .scriptSrc(sources: \"https://static.brokenhands.io\")\n    .reportTo(reportToObject: reportToValue)\n```\n\n```http\nContent-Security-Policy: default-src 'none'; script-src https://static.brokenhands.io; report-to {\"group\":\"vapor-csp\",\"endpoints\":[{\"url\":\"https:\\/\\/csp-report.brokenhands.io\\/csp-reports\"}],\"include_subdomains\":true,\"max_age\":10886400}\n```\n\nSee [Google Developers - The Reporting API](https://developers.google.com/web/updates/2018/09/reportingapi) for more information on the Report-To directive. \n\n#### Content Security Policy Configuration\n\nTo configure your CSP you can add it to your `ContentSecurityPolicyConfiguration` like so:\n\n```swift\nlet cspBuilder = ContentSecurityPolicy()\n    .defaultSrc(sources: CSPKeywords.none)\n    .scriptSrc(sources: \"https://static.brokenhands.io\")\n    .styleSrc(sources: \"https://static.brokenhands.io\")\n    .imgSrc(sources: \"https://static.brokenhands.io\")\n    .fontSrc(sources: \"https://static.brokenhands.io\")\n    .connectSrc(sources: \"https://*.brokenhands.io\")\n    .formAction(sources: CSPKeywords.`self`)\n    .upgradeInsecureRequests()\n    .blockAllMixedContent()\n    .requireSriFor(values: \"script\", \"style\")\n    .reportUri(uri: \"https://csp-report.brokenhands.io\")\n\nlet cspConfig = ContentSecurityPolicyConfiguration(value: cspBuilder)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(contentSecurityPolicy: cspConfig)\n```\n\n```http\nContent-Security-Policy: default-src 'none'; script-src https://static.brokenhands.io; style-src https://static.brokenhands.io; img-src https://static.brokenhands.io; font-src https://static.brokenhands.io; connect-src https://*.brokenhands.io; form-action 'self'; upgrade-insecure-requests; block-all-mixed-content; require-sri-for script style; report-uri https://csp-report.brokenhands.io\n```\n\nThis policy means that by default everything is blocked, however:\n\n* Scripts can be loaded from `https://static.brokenhands.io`\n* CSS can be loaded from `https://static.brokenhands.io`\n* Images can be loaded from `https://static.brokenhands.io`\n* Fonts can be loaded from `https://static.brokenhands.io`\n* Any JS connections can only be made to any `brokenhands.io` subdomain over HTTPS\n* Form actions go only go to the same site\n* Any HTTP requests will be sent over HTTPS\n* Any attempts to load HTTP content will be blocked\n* Any scripts and style links must have [SRI](https://scotthelme.co.uk/subresource-integrity/) values\n* Any policy violations will be sent to `https://csp-report.brokenhands.io`\n\nCheck out [https://report-uri.io/](https://report-uri.io/) for a free tool to send all of your CSP reports to.\n\n### Page Specific CSP\n\nVapor Security Headers also supports setting the CSP on a route or request basis. If the middleware has been added to the `Middlewares`, you can override the CSP for a request. This allows you to have a strict default CSP, but allow content from extra sources when required, such as only allowing the Javascript for blog comments on the blog page. Create a separate `ContentSecurityPolicyConfiguration` and then add it to the request. For example, inside a route handler, you could do:\n\n```swift\nlet cspConfig = ContentSecurityPolicy()\n    .defaultSrc(sources: CSPKeywords.none)\n    .scriptSrc(sources: \"https://comments.disqus.com\")\n\nlet pageSpecificCSP = ContentSecurityPolicyConfiguration(value: cspConfig)\nreq.contentSecurityPolicy = pageSpecificCSP\n```\n\n```http\ncontent-security-policy: default-src 'none'; script-src https://comments.disqus.com\n```\n\n## Content-Security-Policy-Report-Only\n\nContent-Security-Policy-Report-Only works in exactly the same way as Content-Security-Policy except that any violations will not block content, but they will be reported back to you. This is extremely useful for testing a CSP before rolling it out over your site. You can run both side by side - so for example have a fairly simply policy under Content-Security-Policy but test a more restrictive policy over Content-Security-Policy-Report-Only. The great thing about this is that your users do all your testing for you!\n\nTo configure this, just pass in your policy to the `ContentSecurityPolicyReportOnlyConfiguration`:\n\n```swift\nlet cspConfig = ContentSecurityPolicyReportOnlyConfiguration(value: \"default-src https:; report-uri https://csp-report.brokenhands.io\")\n        \nlet securityHeadersFactory = SecurityHeadersFactory().with(contentSecurityPolicyReportOnly: cspConfig)  \n```\n\n```http\ncontent-security-policy-report-only: default-src https:; report-uri https://csp-report.brokenhands.io\n```\n\nThe [above blog post](https://scotthelme.co.uk/content-security-policy-an-introduction/) goes into more details about this.\n\n## X-XSS-Protection\n\nX-XSS-Protection configures the browser's cross-site scripting filter. This package configures the header to be disabled, which (surprisingly) offers security benefits. See [this article on MDN for more information](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection).\n\n```swift\nlet xssProtectionConfig = XSSProtectionConfiguration()\n    \nlet securityHeadersFactory = SecurityHeadersFactory().with(XSSProtection: xssProtectionConfig)\n```\n\n```http\nx-xss-protection: 0\n```\n\n## X-Content-Type-Options\n\nX-Content-Type-Options stops a browser from trying to MIME-sniff content types from requests and makes sure that the declared content type is used. It only has one option, which is `nosniff`. To use this, set your `ContentTypeOptionsConfiguration` as so (this is set by default on any `SecurityHeaders` object):\n\n```swift\nlet contentTypeConfig = ContentTypeOptionsConfiguration(option: .nosniff)\n    \nlet securityHeadersFactory = SecurityHeadersFactory().with(contentTypeOptions: contentTypeConfig)\n```\n\n```http\nx-content-type-options: nosniff\n```\n\nTo disable it:\n\n```swift\nlet contentTypeConfig = ContentTypeOptionsConfiguration(option: .none)\n```\n\n## X-Frame-Options\n\nThe X-Frame-Options header is for click-jacking attacks and tells the browser whether your site can be framed. To stop your site from being framed completely (the default setting):\n\n```swift\nlet frameOptionsConfig = FrameOptionsConfiguration(option: .deny)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(frameOptions: frameOptionsConfig)\n```\n\n```http\nx-frame-options: DENY\n```\n\nTo allow you to frame your own site:\n\n```swift\nlet frameOptionsConfig = FrameOptionsConfiguration(option: .sameOrigin)\n```\n\n```http\nx-frame-options: SAMEORIGIN\n```\n\nTo allow a specific site to frame yours, use:\n\n```swift\nlet frameOptionsConfig = FrameOptionsConfiguration(option: .allow(from: \"https://mytrustedsite.com\"))\n```\n\n```http\nx-frame-options: ALLOW-FROM https://mytrustedsite.com\n```\n\n## Strict-Transport-Security\n\nStrict-Transport-Security is an improvement over 301/302 redirects or HTTPS forwarding. Browsers will default to HTTP when you navigate to an address but HSTS (HTTP Strict Transport Security) tells the browser that it should always connect over HTTPS, so all future requests will be HTTPS, even if you click on an HTTP link. By default this is not turned on with the Security Headers library as it can cause issues if you haven't got HTTPS set up properly. If you specify this header and then at a future date you don't renew your SSL certificate or disable SSL then the browser will refuse to load your site! However, it is highly recommended as it ensures that all connections are over HTTPS, even if a user clicks on an HTTP link.\n\nThe default configuration is `max-age=31536000; includeSubDomains; preload`. This tells the browser to force HTTPS for a year, and for *every* subdomain as well. So if you specify this, make sure you have SSL properly configured for all subdomains, e.g. `test.mysite.com`, `dev.mysite.com` etc.\n\nThe `preload` tag tells Chrome that you want to be preloaded. This will add you to the preload list, which means that the browser will automatically know you want an HTTPS connection before you have even visited the site, so removes the initial HTTP handshake the first time you specify the header. However, this has now been superseded and you should now submit your site at [https://hstspreload.org](https://hstspreload.org). This will add your site to Chrome's source to preload it in the future and it is the list that other browsers use as well. Note that it is difficult to remove yourself from the list (and can take months to get it rolled out to the browsers), so by submitting your site you are effectively guaranteeing working HTTPS for the rest of the life of your site. However, these days it shouldn't be a problem - use [Let's Encrypt](https://letsencrypt.org)! **Note**: You should be careful about using this on deployment sites such as Heroku as it may cause issues.\n\nTo use the Strict-Transport-Security header, you can configure and add it as so (default values are shown):\n\n```swift\nlet strictTransportSecurityConfig = StrictTransportSecurityConfiguration(maxAge: 31536000, includeSubdomains: true, preload: true)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(strictTransportSecurity: strictTransportSecurityConfig)\n```\n\n```http\nstrict-transport-security: max-age=31536000; includeSubDomains; preload\n```\n\n## Redirect HTTP to HTTPS\n\nIf Strict-Transport-Security is not enough to accomplish a forwarding connection to HTTPS from the browsers, you can opt to add an additional middleware who provides this redirection if clients try to reach your site with an HTTP connection.\n\nTo use the HTTPS Redirect Middleware, you can add the following line in **configure.swift** to enable the middleware. This must be done before `securityHeadersFactory.build()` to ensure HSTS works:\n\n```swift\napp.middleware.use(HTTPSRedirectMiddleware())\n```\n\nThe `HTTPSRedirectMiddleware` allows you to set an array of allowed hosts that the application can redirect to. This prevents attackers poisoning the `Host` header and forcing a redirect to a domain under their control. To use this, provide the list of allowed hosts to the initialiser:\n\n```swift\napp.middleware.use(HTTPSRedirectMiddleware(allowedHosts: [\"www.brokenhands.io\", \"brokenhands.io\", \"static.brokenhands.io\"))\n```\n\nAny attempts to redirect to another host, for example `attacker.com` will result in a **400 Bad Request** response.\n\n## Server\n\nThe Server header is usually hidden from responses in order to not give away what type of server you are running and what version you are using. This is to stop attackers from scanning your site and using known vulnerabilities against it easily. By default Vapor does not show the server header in responses for this reason.\n\nHowever, it can be fun to add in a custom server configuration for a bit of personalization, such as your website name, or company name (look at Github's response) and the `ServerConfiguraiton` allows this. So, for example, if I wanted my `Server` header to be `brokenhands.io`, I would configure it like:\n\n```swift\nlet serverConfig = ServerConfiguration(value: \"brokenhands.io\")\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(server: serverConfig)\n```\n\n```http\nserver: brokenhands.io\n```\n\n## Referrer Policy\n\nThe Referrer Policy is the latest header to have been introduced (the spec can be found [here](https://www.w3.org/TR/referrer-policy/)). It basically defines when the `Referrer` header can be sent with a request. You may want to not send the header when going from HTTPS to HTTP for example.\n\nThe different options are:\n\n* \"\"\n* \"no-referrer\"\n* \"no-referrer-when-downgrade\"\n* \"same-origin\"\n* \"origin\"\n* \"strict-origin\"\n* \"origin-when-cross-origin\"\n* \"strict-origin-when-cross-origin\"\n* \"unsafe-url\"\n\nI won't go into details about each one, I will point you in the direction of a far better explanation [by Scott Helme](https://scotthelme.co.uk/a-new-security-header-referrer-policy/).\n\n```swift\nlet referrerPolicyConfig = ReferrerPolicyConfiguration(.noReferrer)\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(referrerPolicy: referrerPolicyConfig)\n```\n\n```http\nreferrer-policy: no-referrer\n```\n\nYou can also [set a fallback policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy).\n\n```swift\nlet referrerPolicyConfig = ReferrerPolicyConfiguration([.noReferrer, .strictOriginWhenCrossOrigin])\n\nlet securityHeadersFactory = SecurityHeadersFactory().with(referrerPolicy: referrerPolicyConfig)\n```\n\n```http\nreferrer-policy: no-referrer, strict-origin-when-cross-origin\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrokenhandsio%2Fvaporsecurityheaders","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrokenhandsio%2Fvaporsecurityheaders","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrokenhandsio%2Fvaporsecurityheaders/lists"}