Website optimization and general configuration Part 3: CORS and headers security – policies and hardening

How to use CORS headers?

To use CORS headers, you should input the code in your vhost config file or add as apache directives in your hosting panel options (if such). The code looks like the following:

Header set Strict-Transport-Security: "max-age=31536000; includeSubDomains; preload"
Header set Referrer-Policy: "strict-origin"
Header set X-XSS-Protection: "1; mode=block"
Header always set Feature-Policy: "fullscreen 'none'; microphone 'none'"
Header edit Set-Cookie: ^(.*)$ $1;HttpOnly;Secure
Header set Content-security-Policy: "default-src ; script-src ; style-src; font-src; connect-src; frame-src"

Each of the above headers has options e.g. directives, that can be set, as follow:


In order to implement HSTS, a host must declare to a User agent (UA) that it is an HSTS Host by issuing an HSTS Policy. This is done with the addition of the HTTP response header Strict-Transport-Security: max-age=31536000. The max-age directive is required and can be any value from 0 upwards, which is the number of seconds after receiving the policy that the UA is to treat the host issuing it as an HSTS Host.

There is also an optional includeSubDomains directive that can be included at the discretion of the host such as Strict-Transport-Security: max-age=31536000; includeSubDomains. This would, as expected, inform the UA that all subdomains are to be treated as HSTS Hosts also.

It is also possible for a browser to ship with a preloaded list of HSTS Hosts. The Chrome and Firefox browsers both feature a built-in list of sites that will always be treated as HSTS Hosts regardless of the presence of the HSTS response header. Websites can opt in to be included in the list of preloaded hosts and you can view the Chromium Source to see all the hosts already included.

For sites preloaded in the browser, there is no state where communications will take place that does not travel on a secure transport layer. Be that the initial communication, the first communication after wiping the local cache or any communication after a policy would have expired, the user cannot exchange data using HTTP. The browser will afford the protection of HSTS for the applicable hosts at all times. Unfortunately, this solution isn’t really scalable considering the sheer potential for the number of sites that could be included. That said, if all financial institutions, government sites, social networks and any other potentially large target applied to be included, they could mitigate a substantial amount of risk.


The no-referrer value instructs the browser to never send the referer header with requests that are made from your site. This also includes links to pages on your own site.

The browser will not send the referrer header when navigating from HTTPS to HTTP, but will always send the full URL in the referrer header when navigating from HTTP to any origin. It doesn’t matter whether the source and destination are the same sites or not, only the scheme.

The browser will only set the referrer header on requests to the same origin. If the destination is another origin then no referrer information will be sent.

The browser will always set the referrer header to the origin from which the request was made. This will strip any path information from the referrer information.

This value is similar to the origin above but will not allow the secure origin to be sent on an HTTP request, only HTTPS.

The browser will send the full URL to requests to the same origin but only send the origin when requests are cross-origin.

Similar to origin-when-cross-origin above but will not allow any information to be sent when a scheme downgrade happens (the user is navigating from HTTPS to HTTP).

The browser will always send the full URL with any request to any origin.


Valid values include DENY meaning your site can’t be framed, SAMEORIGIN which allows you to frame your own site or ALLOW-FROM which lets you specify sites that are permitted to frame your own site.


The full list of features that can be restricted isn’t final yet but here are a few things you could restrict:

payment (PaymentRequest)

Controlling Origins

Controlling which origins can use which features can be done with the following values:

*  This will allow the current page to use the feature and any nested browsing contexts inside it like iframes.

'self' This will allow the current page to use the feature and any nested browsing contexts like iframes only if they are of the same origin, so for example if you frame your own site on your page.

'none' This feature will be disabled for the current page and any nested browsing contexts like iframes.

<origin(s)> Only the specified origins will be allowed to use this feature. For example or


default-src: loading policy for all resources type in case of a resource type dedicated directive is not defined (fallback)

script-src: which scripts the protected resource can execute

object-src: from where the protected resource can load plugins

style-src: which styles (CSS) the user applies to the protected resource

img-src: from where the protected resource can load images

media-src: Define from where the protected resource can load video and audio

frame-src: from where the protected resource can embed frames

font-src: Define from where the protected resource can load fonts

connect-src: which URIs the protected resource can load using script interfaces

form-action: Define which URIs can be used as the action of HTML form elements

sandbox: Specifies an HTML sandbox policy that the user agent applies to the protected resource

script-nonce: Define script execution by requiring the presence of the specified nonce on script elements

plugin-types: Define the set of plugins that can be invoked by the protected resource by limiting the types of resources that can be embedded

reflected-xss: Instructs a user agent to activate or deactivate any heuristics used to filter or block reflected cross-site scripting attacks, equivalent to the effects of the non-standard X-XSS-Protection header

report-uri: Specifies a URI to which the user agent sends reports about a policy violation

Creating a CSP

You can be as specific or as broad as you like when creating a CSP and fine-tune it so that it meets your requirements exactly. Here are some example policies to show you what’s possible.

Content-Security-Policy: default-src https: allows any assets to be loaded over https from any origin.

Content-Security-Policy: default-src would allow any assets to be loaded from any origin on your domain using any scheme or port.

Content-Security-Policy: default-src only allow assets to be loaded from your domain, over HTTPS and on port 443.

Content-Security-Policy: default-src* would only allow assets to be loaded from your domain over HTTPS on any port.

Wildcards can be used for the scheme, the port and the left-most part of a hostname only.

*://** would match any scheme on any subdomain of, but not itself, and on any port.

Further to this, you can also use the following keywords alongside the ‘self’ keyword mentioned above:

'none' blocks the use of this type of resource.

'self' matches the current origin (but not subdomains).

'unsafe-inline' allows the use of inline JS and CSS.

'unsafe-eval' allows the use of mechanisms like eval().

These can be applied in the following manner:

Content-Security-Policy: default-src 'none'; script-src

would block the loading of any content apart from scripts loaded from your domain over HTTPS.

Content-Security-Policy: default-src 'none'; script-src; style-src 'unsafe-inline'

would be the same as above with the addition of inline CSS.

It’s worth noting that you can’t specify a directive twice, as the second will be ignored.

Content-Security-Policy: script-src; script-src

would result in no scripts being loaded from The correct policy would be:

Content-Security-Policy: script-src

There is also no inheritance from the default source directive.

Content-Security-Policy: default-src https:; script-src

would result in no scripts being loaded over HTTPS from The correct policy would be:

Content-Security-Policy: default-src https:; script-src

Leave a Reply