OWASP Secure Headers Project
Introduction
The OWASP Secure Headers Project (also called OSHP) describes HTTP response headers that your application can use to increase the security of your application. Once set, these HTTP response headers can restrict modern browsers from running into easily preventable vulnerabilities. The OWASP Secure Headers Project intends to raise awareness and use of these headers.
HTTP headers are well-known and also despised. Seeking a balance between usability and security, developers implement functionality through the headers that can make applications more versatile or secure. But in practice how are the headers being implemented? What sites follow the best implementation practices? Big companies, small, all or none?
Description
The OWASP Secure Headers Project aim to provide elements about the following aspects regarding HTTP security headers:
- Guidance about the recommended HTTP security headers that can be leveraged.
- Guidance about the HTTP headers that should be removed.
- Tools to validate an HTTP security header configuration.
- Code libraries that can be leveraged to configure recommended HTTP security headers.
- Statistics about usage of the recommended HTTP security headers.
- REST API allowing to obtain the recommended configuration for different web server.
All the tools provided by the OSHP are gathered under this GitHub organization.
A presentation of the project is available on the OWASP Spotlight Youtube playlist.
Migration
The OWASP Secure Headers Project was migrated from the old website to the GitHub OWASP organization.
The following projects are now archived, they are initiatives that are now replaced by new projects:
Security headers usage statistics
We provide statistics, updated every month, about HTTP response security headers usage mentioned by the OWASP Secure Headers Project.
They are available through this GitHub project.
Security headers usage validator
We provide a venom tests suite to validate an HTTP security response header configuration against OWASP Secure Headers Project recommendation.
It is available through this GitHub project.
Discussions and information
We use the GitHub discussions area for discussions about the project as well as spreading global information about it.
Contributors
Licensing
OWASP Secure Headers is free to use. It is licensed under the Apache 2.0 License.
Response Headers
Header lifecycle flow:
Working draft -> Active -> Almost deprecated -> Deprecated
.
Working draft
Active
- HTTP Strict Transport Security
- X-Frame-Options
- X-Content-Type-Options
- Content-Security-Policy
- X-Permitted-Cross-Domain-Policies
- Referrer-Policy
- Clear-Site-Data
- Cross-Origin-Embedder-Policy
- Cross-Origin-Opener-Policy
- Cross-Origin-Resource-Policy
- Cache-Control
Almost deprecated
Deprecated
HTTP Strict Transport Security
HTTP Strict Transport Security (also named HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections, and never via the insecure HTTP protocol. HSTS is an IETF standards track protocol and is specified in RFC 6797. A server implements an HSTS policy by supplying a header (Strict-Transport-Security
) over an HTTPS connection (HSTS headers over HTTP are ignored).
Values
Value | Description |
---|---|
max-age=SECONDS |
The time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS. |
includeSubDomains |
If this optional parameter is specified, this rule applies to all of the site’s subdomains as well. |
Example
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
References
- https://tools.ietf.org/html/rfc6797
- https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Strict_Transport_Security_Cheat_Sheet.html
- https://owasp.org/www-project-web-security-testing-guide/stable/4-Web_Application_Security_Testing/02-Configuration_and_Deployment_Management_Testing/07-Test_HTTP_Strict_Transport_Security.html
- https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
- https://www.chromium.org/hsts
- https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security
- https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html
- https://blogs.windows.com/msedgedev/2015/06/09/http-strict-transport-security-comes-to-internet-explorer-11-on-windows-8-1-and-windows-7/
X-Frame-Options
The X-Frame-Options
response header (also named XFO) improves the protection of web applications against clickjacking. It instructs the browser whether the content can be displayed within frames.
The Content-Security-Policy (CSP) frame-ancestors directive obsoletes the X-Frame-Options header. If a resource has both policies, the CSP frame-ancestors policy will be enforced and the X-Frame-Options policy will be ignored.
Values
Value | Description |
---|---|
deny |
No rendering within a frame. |
sameorigin |
No rendering if origin mismatch. |
allow-from: DOMAIN |
Allows rendering if framed by frame loaded from DOMAIN (not supported by modern browsers). |
Example
X-Frame-Options: deny
References
- https://tools.ietf.org/html/rfc7034
- https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-01
- https://tools.ietf.org/html/draft-ietf-websec-frame-options-00
- https://developer.mozilla.org/en-US/docs/Web/HTTP/X-Frame-Options
- https://portswigger.net/web-security/clickjacking
- https://blogs.msdn.microsoft.com/ieinternals/2010/03/30/combating-clickjacking-with-x-frame-options/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors
X-Content-Type-Options
Setting this header will prevent the browser from interpreting files as a different MIME type to what is specified in the Content-Type
HTTP header (e.g. treating text/plain
as text/css
).
Values
Value | Description |
---|---|
nosniff |
Will prevent the browser from MIME-sniffing a response away from the declared content-type. |
Example
X-Content-Type-Options: nosniff
References
- https://msdn.microsoft.com/en-us/library/gg622941%28v=vs.85%29.aspx
- https://blogs.msdn.microsoft.com/ie/2008/09/02/ie8-security-part-vi-beta-2-update/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
Content-Security-Policy
A Content Security Policy (also named CSP) requires careful tuning and precise definition of the policy. If enabled, CSP has significant impact on the way browsers render pages (e.g., inline JavaScript is disabled by default and must be explicitly allowed in the policy). CSP prevents a wide range of attacks, including cross-site scripting and other cross-site injections.
Values
Directive | Description |
---|---|
base-uri |
Define the base URI for relative URIs. |
default-src |
Define loading policy for all resources type in case a resource type’s dedicated directive is not defined (fallback). |
script-src |
Define which scripts the protected resource can execute. |
object-src |
Define from where the protected resource can load plugins. |
style-src |
Define which styles (CSS) can be applied to the protected resource. |
img-src |
Define from where the protected resource can load images. |
media-src |
Define from where the protected resource can load video and audio. |
frame-src |
(Deprecated and replaced by child-src ) Define from where the protected resource can embed frames. |
child-src |
Define from where the protected resource can embed frames. |
frame-ancestors |
Define from where the protected resource can be embedded in frames. |
font-src |
Define from where the protected resource can load fonts. |
connect-src |
Define which URIs the protected resource can load using script interfaces. |
manifest-src |
Define from where the protected resource can load manifests. |
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 |
Instruct the 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. |
block-all-mixed-content |
Prevent the user agent from loading mixed content. |
upgrade-insecure-requests |
Instruct the user agent to download insecure HTTP resources using HTTPS. |
referrer |
(Deprecated) Define information the user agent can send in the Referer header. |
report-uri |
(Deprecated and replaced by report-to ) Specifies a URI to which the user agent sends reports about policy violation. |
report-to |
Specifies a group (defined in the Report-To header) to which the user agent sends reports about policy violation. |
Example
Content-Security-Policy: script-src 'self'
References
- https://www.w3.org/TR/CSP/
- https://developer.mozilla.org/en-US/docs/Web/Security/CSP
- https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html
- https://scotthelme.co.uk/content-security-policy-an-introduction/
- https://report-uri.io
- https://content-security-policy.com
- https://report-uri.com/home/generate
- https://csp-evaluator.withgoogle.com/
X-Permitted-Cross-Domain-Policies
A cross-domain policy file is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains. When clients request content hosted on a particular source domain and that content makes requests directed towards a domain other than its own, the remote domain needs to host a cross-domain policy file that grants access to the source domain, allowing the client to continue the transaction. Normally a meta-policy is declared in the master policy file, but for those who can’t write to the root directory, they can also declare a meta-policy using the X-Permitted-Cross-Domain-Policies
HTTP response header.
Values
Value | Description |
---|---|
none |
No policy files are allowed anywhere on the target server, including this master policy file. |
master-only |
Only this master policy file is allowed. |
by-content-type |
[HTTP/HTTPS only] Only policy files served with Content-Type: text/x-cross-domain-policy are allowed. |
by-ftp-filename |
[FTP only] Only policy files whose file names are crossdomain.xml (i.e. URLs ending in /crossdomain.xml) are allowed. |
all |
All policy files on this target domain are allowed. |
Example
X-Permitted-Cross-Domain-Policies: none
References
- https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/xdomain.html
- https://danielnixon.org/http-security-headers/
- https://rorsecurity.info/portfolio/new-http-headers-for-more-security
- https://github.com/twitter/secureheaders/issues/88
- https://gf.dev/cross-domain-policy-test
Referrer-Policy
The Referrer-Policy
HTTP header governs which referrer information, sent in the Referer
header, should be included with requests made.
Values
Value | Description |
---|---|
no-referrer |
The Referer header will be omitted entirely. No referrer information is sent along with requests. |
no-referrer-when-downgrade |
This is the user agent’s default behavior if no policy is specified. The origin is sent as referrer to a-priori as-much-secure destination (HTTPS → HTTPS), but isn’t sent to a less secure destination (HTTPS → HTTP). |
origin |
Only send the origin of the document as the referrer in all cases. (e.g. the document https://example.com/page.html will send the referrer https://example.com/ .) |
origin-when-cross-origin |
Send a full URL when performing a same-origin request, but only send the origin of the document for other cases. |
same-origin |
A referrer will be sent for same-site origins, but cross-origin requests will contain no referrer information. |
strict-origin |
Only send the origin of the document as the referrer to a-priori as-much-secure destination (HTTPS → HTTPS), but don’t send it to a less secure destination (HTTPS → HTTP). |
strict-origin-when-cross-origin |
Send a full URL when performing a same-origin request, only send the origin of the document to a-priori as-much-secure destination (HTTPS → HTTPS), and send no header to a less secure destination (HTTPS → HTTP). |
unsafe-url |
Send a full URL (stripped from parameters) when performing a same-origin or cross-origin request. |
Example
Referrer-Policy: no-referrer
References
- https://www.w3.org/TR/referrer-policy/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
Clear-Site-Data
The Clear-Site-Data header clears browsing data (cookies, storage, cache) associated with the requesting website. It allows web developers to have more control over the data stored locally by a browser for their origins (source Mozilla MDN). This header is useful for example, during a logout process, in order to ensure that all stored content on the client side like cookies, storage and cache are removed.
Values
Value | Description |
---|---|
"cache" |
Indicates that the server wishes to remove locally cached data for the origin of the response URL. |
"cookies" |
Indicates that the server wishes to remove all cookies for the origin of the response URL. HTTP authentication credentials are also cleared out. This affects the entire registered domain, including subdomains. |
"storage" |
Indicates that the server wishes to remove all DOM storage for the origin of the response URL. |
"executionContexts" |
Indicates that the server wishes to reload all browsing contexts for the origin of the response. Currently, this value is only supported by a small subset of browsers. |
"*" |
Indicates that the server wishes to clear all types of data for the origin of the response. If more data types are added in future versions of this header, they will also be covered by it. |
Example
Clear-Site-Data: "cache","cookies","storage"
References
- https://w3c.github.io/webappsec-clear-site-data/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data
- https://www.chromestatus.com/feature/4713262029471744
- https://github.com/w3c/webappsec-clear-site-data
- https://github.com/w3c/webappsec-clear-site-data/tree/master/demo
Cross-Origin-Embedder-Policy
This response header (also named COEP) prevents a document from loading any cross-origin resources that don’t explicitly grant the document permission (source Mozilla MDN).
Values
Value | Description |
---|---|
unsafe-none |
Allows the document to fetch cross-origin resources without giving explicit permission through the CORS protocol or the Cross-Origin-Resource-Policy header (it is the default value). |
require-corp |
A document can only load resources from the same origin, or resources explicitly marked as loadable from another origin. |
Example
Cross-Origin-Embedder-Policy: require-corp
References
- https://html.spec.whatwg.org/multipage/origin.html#coep
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy
- https://caniuse.com/?search=Cross-Origin-Embedder-Policy
- https://web.dev/coop-coep/
- https://web.dev/why-coop-coep/
- https://web.dev/cross-origin-isolation-guide/
Cross-Origin-Opener-Policy
This response header (also named COOP) allows you to ensure a top-level document does not share a browsing context group with cross-origin documents. COOP will process-isolate your document and potential attackers can’t access to your global object if they were opening it in a popup, preventing a set of cross-origin attacks dubbed XS-Leaks (source Mozilla MDN).
Values
Value | Description |
---|---|
unsafe-none |
Allows the document to be added to its opener’s browsing context group unless the opener itself has a COOP of same-origin or same-origin-allow-popups (it is the default value). |
same-origin-allow-popups |
Retains references to newly opened windows or tabs which either don’t set COOP or which opt out of isolation by setting a COOP of unsafe-none . |
same-origin |
Isolates the browsing context exclusively to same-origin documents. Cross-origin documents are not loaded in the same browsing context. |
Example
Cross-Origin-Opener-Policy: same-origin
References
- https://html.spec.whatwg.org/multipage/origin.html#cross-origin-opener-policies
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy
- https://web.dev/coop-coep/
- https://web.dev/why-coop-coep/
- https://github.com/xsleaks/xsleaks
- https://portswigger.net/daily-swig/xs-leak
- https://portswigger.net/research/xs-leak-detecting-ids-using-portal
- https://web.dev/cross-origin-isolation-guide/
Cross-Origin-Resource-Policy
This response header (also named CORP) allows to define a policy that lets web sites and applications opt in to protection against certain requests from other origins (such as those issued with elements like <script>
and <img>
), to mitigate speculative side-channel attacks, like Spectre, as well as Cross-Site Script Inclusion (XSSI) attacks (source Mozilla MDN).
Values
Value | Description |
---|---|
same-site |
Only requests from the same Site can read the resource. |
same-origin |
Only requests from the same Origin (i.e. scheme + host + port) can read the resource. |
cross-origin |
Requests from any Origin (both same-site and cross-site ) can read the resource. Browsers are using this policy when an CORP header is not specified. |
Example
Cross-Origin-Resource-Policy: same-origin
References
- https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy
- https://resourcepolicy.fyi/
- https://web.dev/cross-origin-isolation-guide/
Cache-Control
This header holds directives (instructions) for caching in both requests and responses. If a given directive is in a request, it does not mean this directive is in the response (source Mozilla MDN). Specify the capability of a resource to be cached is important to prevent exposure of information via the cache.
The headers named Expires and Pragma can be used in addition to the Cache-Control header. Pragma header can be used for backwards compatibility with the HTTP/1.0 caches. However, Cache-Control is the recommended way to define the caching policy.
Values applicable for HTTP responses
Value | Description |
---|---|
must-revalidate |
Indicates that once a resource becomes stale, caches do not use their stale copy without successful validation on the origin server. |
no-cache |
The response may be stored by any cache, even if the response is normally non-cacheable. However, the stored response MUST always go through validation with the origin server first before using it. |
no-store |
The response may not be stored in any cache. |
no-transform |
An intermediate cache or proxy cannot edit the response body, Content-Encoding , Content-Range , or Content-Type . |
public |
The response may be stored by any cache, even if the response is normally non-cacheable. |
private |
The response may be stored only by a browser’s cache, even if the response is normally non-cacheable. |
proxy-revalidate |
Like must-revalidate , but only for shared caches (e.g., proxies). Ignored by private caches. |
max-age=<seconds> |
The maximum amount of time a resource is considered fresh. Unlike Expires, this directive is relative to the time of the request. |
s-maxage=<seconds> |
Overrides max-age or the Expires header, but only for shared caches (e.g., proxies). Ignored by private caches. |
Extended values
The following directives are not part of the core HTTP caching standards document. Therefore, check this table for their support.
Value | Description |
---|---|
immutable |
Indicates that the response body will not change over time. |
stale-while-revalidate=<seconds> |
Indicates the client can accept a stale response, while asynchronously checking in the background for a fresh one. The seconds value indicates how long the client can accept a stale response. |
stale-if-error=<seconds> |
Indicates the client can accept a stale response if the check for a fresh one fails. The seconds value indicates how long the client can accept the stale response after the initial expiration. |
Example
No caching allowed, clear any previously cached resources and include support for HTTP/1.0 caches:
Cache-Control: no-store, max-age=0
Pragma: no-cache
Caching allowed with a cache duration of one week:
Cache-Control: public, max-age=604800
References
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Pragma
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
- https://datatracker.ietf.org/doc/html/rfc7234
- https://cwe.mitre.org/data/definitions/524.html
- https://cwe.mitre.org/data/definitions/525.html
- https://portswigger.net/web-security/web-cache-poisoning
- https://portswigger.net/research/practical-web-cache-poisoning
- https://portswigger.net/research/web-cache-entanglement
Permissions Policy
Working draft.
The Permissions-Policy header replaces the existing Feature-Policy header for controlling delegation of permissions and powerful features. The header uses a structured syntax, and allows sites to more tightly restrict which origins can be granted access to features (source Chrome platform status).
Values
Value | Description |
---|---|
accelerometer |
Controls whether the current document is allowed to gather information about the acceleration of the device through the Accelerometer interface. |
ambient-light-sensor |
Controls whether the current document is allowed to gather information about the amount of light in the environment around the device through the AmbientLightSensor interface. |
autoplay |
Controls whether the current document is allowed to autoplay media requested through the HTMLMediaElement interface. |
battery |
Controls whether the use of the Battery Status API is allowed. |
camera |
Controls whether the current document is allowed to use video input devices. |
display-capture |
Controls whether or not the current document is permitted to use the getDisplayMedia() method to capture screen contents. |
document-domain |
Controls whether the current document is allowed to set document.domain. |
encrypted-media |
Controls whether the current document is allowed to use the Encrypted Media Extensions API (EME). |
execution-while-not-rendered |
Controls whether tasks should execute in frames while they’re not being rendered (e.g. if an iframe is hidden or display: none ). |
execution-while-out-of-viewport |
Controls whether tasks should execute in frames while they’re outside of the visible viewport. |
fullscreen |
Controls whether the current document is allowed to use Element.requestFullScreen() . |
geolocation |
Controls whether the current document is allowed to use the Geolocation Interface. |
gyroscope |
Controls whether the current document is allowed to gather information about the orientation of the device through the Gyroscope interface. |
layout-animations |
Controls whether the current document is allowed to show layout animations. |
legacy-image-formats |
Controls whether the current document is allowed to display images in legacy formats. |
magnetometer |
Controls whether the current document is allowed to gather information about the orientation of the device through the Magnetometer interface. |
microphone |
Controls whether the current document is allowed to use audio input devices. |
midi |
Controls whether the current document is allowed to use the Web MIDI API. |
navigation-override |
Controls the availability of mechanisms that enables the page author to take control over the behavior of spatial navigation, or to cancel it outright. |
oversized-images |
Controls whether the current document is allowed to download and display large images. |
payment |
Controls whether the current document is allowed to use the Payment Request API. |
picture-in-picture |
Controls whether the current document is allowed to play a video in a Picture-in-Picture mode via the corresponding API. |
publickey-credentials-get |
Controls whether the current document is allowed to use the Web Authentication API to retrieve already stored public-key credentials, i.e. via navigator.credentials.get({publicKey: ..., ...}) . |
sync-xhr |
Controls whether the current document is allowed to make synchronous XMLHttpRequest requests. |
usb |
Controls whether the current document is allowed to use the WebUSB API. |
vr |
Controls whether the current document is allowed to use the WebVR API. |
wake-lock |
Controls whether the current document is allowed to use Wake Lock API to indicate that device should not enter power-saving mode. |
screen-wake-lock |
Controls whether the current document is allowed to use Screen Wake Lock API to indicate that device should not turn off or dim the screen. |
web-share |
Controls whether or not the current document is allowed to use the Navigator.share() of Web Share API to share text, links, images, and other content to arbitrary destinations of user’s choice, e.g. mobile apps. |
xr-spatial-tracking |
Controls whether or not the current document is allowed to use the WebXR Device API to interact with a WebXR session. |
Example
Permissions-Policy: accelerometer=(),autoplay=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(self),usb=(),web-share=(),xr-spatial-tracking=()
Remarks
Usage of all possible values from the table above raised the following error on Chrome 90.0.4430.212 and Edge 90.0.818.62:
Error with Permissions-Policy header: Unrecognized feature: 'ambient-light-sensor'.
Error with Permissions-Policy header: Unrecognized feature: 'battery'.
Error with Permissions-Policy header: Unrecognized feature: 'execution-while-not-rendered'.
Error with Permissions-Policy header: Unrecognized feature: 'execution-while-out-of-viewport'.
Error with Permissions-Policy header: Unrecognized feature: 'layout-animations'.
Error with Permissions-Policy header: Unrecognized feature: 'legacy-image-formats'.
Error with Permissions-Policy header: Unrecognized feature: 'navigation-override'.
Error with Permissions-Policy header: Unrecognized feature: 'oversized-images'.
Error with Permissions-Policy header: Unrecognized feature: 'vr'.
Error with Permissions-Policy header: Unrecognized feature: 'wake-lock'.
References
- https://github.com/w3c/webappsec-permissions-policy/blob/main/permissions-policy-explainer.md
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy#directives
- https://caniuse.com/permissions-policy
- https://www.w3.org/TR/permissions-policy-1/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
- https://www.chromestatus.com/feature/5745992911552512
Feature-Policy
Almost deprecated.
⚠️ Warning: This header was split into Permissions-Policy and Document-Policy and will be considered deprecated once all impacted features are moved off of feature policy.
The Feature-Policy header is an experimental feature that allows developers to selectively enable and disable use of various browser features and APIs.
The two most well supported values are microphone
and camera
. For all the other ones, please consult this page.
Values
Value | Description |
---|---|
accelerometer |
Controls access to accelerometer sensors on the device. |
ambient-light-sensor |
Controls access to ambient light sensors on the device. |
autoplay |
Controls access to autoplay through play() and the autoplay attribute. |
battery |
Controls access to the BatteryManager API. |
camera |
Controls access to video input devices. |
display-capture |
Controls access to capturing the display output. |
document-domain |
Controls access to setting document.domain . |
encrypted-media |
Controls whether requestMediaKeySystemAccess() is allowed. |
fullscreen |
Controls whether requestFullscreen() is allowed. |
geolocation |
Controls access to the Geolocation interface. |
gyroscope |
Controls access to gyroscope sensors on the device. |
magnetometer |
Controls access to magnetometer sensors on the device. |
microphone |
Controls access to audio input devices. |
midi |
Controls access to requestMIDIAccess() method. |
navigation-override |
Controls access to override of the spatial navigation API. |
payment |
Controls access to the PaymentRequest interface. |
picture-in-picture |
Controls access to picture-in-picture. |
speaker |
Controls access to audio output devices. |
usb |
Controls access to USB devices. |
vibrate |
(deprecated) Controls access to the vibrate() method. |
vr |
(deprecated) Controls access to VR displays. |
Some experimental features are not present in this list, please check the references below for a complete list.
Example
Feature-Policy: vibrate 'none'; geolocation 'none'
References
- https://w3c.github.io/webappsec-feature-policy/
- https://scotthelme.co.uk/a-new-security-header-feature-policy/
- https://github.com/w3c/webappsec-feature-policy/blob/master/features.md
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
- https://caniuse.com/permissions-policy
Expect-CT
Deprecated.
⚠️ Warning: This header will likely become obsolete in June 2021. Since May 2018 new certificates are expected to support SCTs by default. Certificates before March 2018 were allowed to have a lifetime of 39 months, those will all be expired in June 2021.
The Expect-CT
header is used by a server to indicate that browsers should evaluate connections to the host for Certificate Transparency compliance.
In Chrome 61 (Aug 2017) Chrome enabled its enforcement via SCT by default (source). You can still use this header to specify an report-uri
.
This header comes from the (now expired) internet draft Expect-CT Extension for HTTP.
Values
Value | Description |
---|---|
report-uri |
(Optional) Indicates the URL to which the browser should report Expect-CT failures. |
enforce |
(Optional) A valueless directive that, if present, signals to the browser that compliance to the CT Policy should be enforced (rather than report-only) and that the browser should refuse future connections that violate its CT Policy. When both the enforce and report-uri directives are present, the configuration is referred to as an “enforce-and-report” configuration, signalling to the browser both that compliance to the CT Policy should be enforced and that violations should be reported. |
max-age |
Specifies the number of seconds after the response is received the browser should remember and enforce certificate transparency compliance. |
Example
Expect-CT: max-age=86400, enforce, report-uri="https://foo.example/report"
References
- https://datatracker.ietf.org/doc/html/rfc9163
- https://scotthelme.co.uk/a-new-security-header-expect-ct/
- https://www.chromestatus.com/feature/5677171733430272
Public-Key-Pins
Deprecated.
⚠️ Warning: This header has been deprecated by all major browsers and is no longer recommended. Avoid using it, and update existing code if possible;
HTTP Public Key Pinning (HPKP) is a security mechanism which allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates. (For example, sometimes attackers can compromise certificate authorities, and then can mis-issue certificates for a web origin.).
The HTTPS web server serves a list of public key hashes, and on subsequent connections clients expect that server to use one or more of those public keys in its certificate chain. Deploying HPKP safely will require operational and organizational maturity due to the risk that hosts may make themselves unavailable by pinning to a set of public key hashes that becomes invalid. With care, host operators can greatly reduce the risk of man-in-the-middle (MITM) attacks and other false authentication problems for their users without incurring undue risk.
Deprecation Reason
Criticism and concern revolved around malicious or human error scenarios known as HPKP Suicide and Ransom PKP. In such scenarios, a website owner would have their ability to publish new contents to their domain severely hampered by either losing access to their own keys or having new keys announced by a malicious attacker.
Values
Value | Description |
---|---|
pin-sha256="<sha256>" |
The quoted string is the Base64 encoded Subject Public Key Information (SPKI) fingerprint. It is possible to specify multiple pins for different public keys. Some browsers might allow other hashing algorithms than SHA-256 in the future. |
max-age=SECONDS |
The time, in seconds, that the browser should remember that this site is only to be accessed using one of the pinned keys. |
includeSubDomains |
If this optional parameter is specified, this rule applies to all of the site’s subdomains as well. |
report-uri="<URL>" |
If this optional parameter is specified, pin validation failures are reported to the given URL. |
Example
Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
References
- https://tools.ietf.org/html/rfc7469
- https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning#HTTP_pinning
- https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning
- https://developer.mozilla.org/en-US/docs/Web/Security/Public_Key_Pinning
- https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html
- https://labs.detectify.com/2016/07/05/what-hpkp-is-but-isnt/
- https://blog.qualys.com/ssllabs/2016/09/06/is-http-public-key-pinning-dead
- https://scotthelme.co.uk/im-giving-up-on-hpkp/
- https://groups.google.com/a/chromium.org/forum/m/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ
X-XSS-Protection
Deprecated.
⚠️ Warning: The X-XSS-Protection header has been deprecated by modern browsers and its use can introduce additional security issues on the client side. As such, it is recommended to set the header as
X-XSS-Protection: 0
in order to disable the XSS Auditor, and not allow it to take the default behavior of the browser handling the response. Please useContent-Security-Policy
instead.
This header enables the cross-site scripting (XSS) filter in your browser.
Values
Value | Description |
---|---|
0 |
Filter disabled. |
1 |
Filter enabled. If a cross-site scripting attack is detected, in order to stop the attack, the browser will sanitize the page. |
1; mode=block |
Filter enabled. Rather than sanitize the page, when a XSS attack is detected, the browser will prevent rendering of the page. |
1; report=http://[YOURDOMAIN]/your_report_URI |
Filter enabled. The browser will sanitize the page and report the violation. This is a Chromium function utilizing CSP violation reports to send details to a URI of your choice. |
Example
X-XSS-Protection: 0
References
- https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- https://www.chromestatus.com/feature/5021976655560704
- https://bugzilla.mozilla.org/show_bug.cgi?id=528661
- https://blogs.windows.com/windowsexperience/2018/07/25/announcing-windows-10-insider-preview-build-17723-and-build-18204/
- https://github.com/zaproxy/zaproxy/issues/5849
- https://scotthelme.co.uk/security-headers-updates/#removing-the-x-xss-protection-header
- https://portswigger.net/daily-swig/google-chromes-xss-auditor-goes-back-to-filter-mode
- https://owasp.org/www-community/attacks/xss/
- https://www.virtuesecurity.com/blog/understanding-xss-auditor/
- https://www.veracode.com/blog/2014/03/guidelines-for-setting-security-headers
- http://zinoui.com/blog/security-http-headers#x-xss-protection
Browser Support
A reference is provided, for each header, to a site always providing up-to-date information.
Technical Resources
This section provides a list of tools as well as documents to understand, analyze, develop and administrate HTTP secure headers to help achieving more secure and trustworthy web systems.
Presentations
Analysis Tools
hsecscan
A security scanner for HTTP response headers.
Github: https://github.com/riramar/hsecscan
humble
A humble, and fast, security-oriented HTTP headers analyzer.
Github: https://github.com/rfc-st/humble
headers
Python script to get some response headers from Alexa top sites file and store in a MySQL database.
Github: https://github.com/oshp/headers/
SecurityHeaders.com
There are services out there that will analyse the HTTP response headers of other sites but I also wanted to add a rating system to the results. The HTTP response headers that this site analyses provide huge levels of protection and it’s important that sites deploy them. Hopefully, by providing an easy mechanism to assess them, and further information on how to deploy missing headers, we can drive up the usage of security based headers across the web.
Site: https://securityheaders.com/
Mozilla Observatory
A Mozilla project designed to help developers, system administrators, and security professionals configure their sites safely and securely.
Site: https://observatory.mozilla.org/
Github: https://github.com/mozilla/http-observatory/
Github: https://github.com/mozilla/http-observatory-website/
Recx Security Analyser
Chrome extension that allows the inspection of security aspects of a site’s HTTP headers, cookies and other key security settings.
Site: https://chrome.google.com/webstore/detail/recx-security-analyser/ljafjhbjenhgcgnikniijchkngljgjda
testssl.sh
Easy to use shell script which tests not only SSL/TLS encryption but also checks common headers and analyzes those. Output is screen, JSON, CSV and HTML.
Github: https://github.com/drwetter/testssl.sh
DrHEADer
DrHEADer helps with the audit of security headers received in response to a single request or a list of requests.
Github: https://github.com/Santandersecurityresearch/DrHeader
API-Security
This is a Python based API-Security framework containing ApiSecurityHeader.py script which will check the above mentioned Security response headers are present and contains the required value.
Github: https://github.com/AmitKulkarni9/API-Security
Development Libraries
Java
Spring Security
Spring Security’s support for adding various security headers to the response.
Site: https://docs.spring.io/spring-security/reference/features/exploits/headers.html
.NET
NWebsec
NWebsec consists of several security libraries for ASP.NET applications.
Site: https://docs.nwebsec.com
NetEscapades.AspNetCore.SecurityHeaders
Small package to allow adding security headers to ASP.NET Core websites.
Github: https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders
Ruby
secure_headers
Security related headers all in one gem.
Github: https://github.com/github/secure_headers
PHP
SecureHeaders
A PHP class aiming to make the use of browser security features more accessible.
Github: https://github.com/aidantwoods/SecureHeaders
secure-headers
PHP Secure Headers for Laravel and non-Laravel projects.
Github: https://github.com/bepsvpt/secure-headers
RACK
rack-secure_headers
Security related HTTP headers for Rack applications.
Github: https://github.com/frodsan/rack-secure_headers
NodeJS
helmet
Module to help secure Express apps with various HTTP headers.
Github: https://github.com/helmetjs/helmet
ember-cli-content-security-policy
This addon makes it easy to use Content Security Policy (CSP) in your project. It can be deployed either via a Content-Security-Policy header sent from the Ember CLI Express server, or as a meta tag in the index.html file.
Github: https://github.com/rwjblue/ember-cli-content-security-policy/
HAPI
blankie
A CSP plugin for hapi.
Github: https://github.com/nlf/blankie
Python
django-csp and django-security
Content Security Policy for Django.
Github: https://github.com/mozilla/django-csp
A collection of models, views, middlewares, and forms to help secure a Django project.
Github: https://github.com/sdelements/django-security
Secure
Secure headers for Python web frameworks.
Github: https://github.com/TypeError/secure
Go
helmet
HTTP security middleware for Go(lang) inspired by HelmetJS.
Github: https://github.com/goddtriffin/helmet
Rust
Best-practice OWASP HTTP response headers for Rust.
Site: https://docs.rs/crate/owasp-headers/latest
Operation Tools
http_hardening
Puppet module to enable, configure and manage secure http headers on web servers.
Supported Web Servers:
- Apache HTTP Server
- NGINX
- Lighttpd
Github: https://github.com/amenezes/http_hardening
Puppet Forge: https://forge.puppet.com/amenezes/http_hardening
Top Websites Examples
HTTP response headers from the top websites in the world.
Command used to extract the headers:
curl -L -A "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" -s -D - https://www.example.com -o /dev/null
$ curl -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36" -s -D - https://www.google.com -o /dev/null
HTTP/2 200
date: Sat, 15 Jan 2022 16:20:55 GMT
expires: -1
cache-control: private, max-age=0
content-type: text/html; charset=UTF-8
strict-transport-security: max-age=31536000
bfcache-opt-in: unload
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
server: gws
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
accept-ranges: none
vary: Accept-Encoding
$ curl -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36" -s -D - https://www.facebook.com -o /dev/null
HTTP/2 200
vary: Accept-Encoding
x-fb-rlafr: 0
document-policy: force-load-at-top
pragma: no-cache
cache-control: private, no-cache, no-store, must-revalidate
expires: Sat, 01 Jan 2000 00:00:00 GMT
x-content-type-options: nosniff
x-xss-protection: 0
content-security-policy-report-only: default-src data: blob: 'self' https://*.fbsbx.com 'unsafe-inline' *.facebook.com 'unsafe-eval' *.fbcdn.net;script-src *.facebook.com *.fbcdn.net 'unsafe-inline' 'unsafe-eval' blob: data: 'self';style-src *.fbcdn.net data: *.facebook.com 'unsafe-inline';connect-src *.facebook.com facebook.com *.fbcdn.net wss://*.facebook.com:* attachment.fbsbx.com blob: *.cdninstagram.com 'self' wss://gateway.facebook.com wss://edge-chat.facebook.com wss://snaptu-d.facebook.com wss://kaios-d-test.facebook.com/ wss://kaios-d.facebook.com/ *.fbsbx.com;font-src data: *.facebook.com *.fbcdn.net *.fbsbx.com;img-src *.fbcdn.net *.facebook.com data: https://*.fbsbx.com facebook.com *.cdninstagram.com fbsbx.com fbcdn.net blob: android-webview-video-poster:;media-src *.cdninstagram.com blob: *.fbcdn.net *.fbsbx.com www.facebook.com *.facebook.com data:;frame-src *.facebook.com *.fbsbx.com fbsbx.com data: *.fbcdn.net;worker-src blob: *.facebook.com data:;report-uri https://www.facebook.com/csp/reporting/?m=c&minimize=0;
content-security-policy: default-src data: blob: 'self' https://*.fbsbx.com 'unsafe-inline' *.facebook.com 'unsafe-eval' *.fbcdn.net;script-src *.facebook.com *.fbcdn.net 'unsafe-inline' 'unsafe-eval' blob: data: 'self';style-src *.fbcdn.net data: *.facebook.com 'unsafe-inline';connect-src *.facebook.com facebook.com *.fbcdn.net wss://*.facebook.com:* attachment.fbsbx.com blob: *.cdninstagram.com 'self' wss://gateway.facebook.com wss://edge-chat.facebook.com wss://snaptu-d.facebook.com wss://kaios-d-test.facebook.com/ wss://kaios-d.facebook.com/ *.fbsbx.com;font-src data: *.facebook.com *.fbcdn.net *.fbsbx.com;img-src *.fbcdn.net *.facebook.com data: https://*.fbsbx.com facebook.com *.cdninstagram.com fbsbx.com fbcdn.net blob: android-webview-video-poster:;media-src *.cdninstagram.com blob: *.fbcdn.net *.fbsbx.com www.facebook.com *.facebook.com data:;frame-src *.facebook.com *.fbsbx.com fbsbx.com data: *.fbcdn.net;worker-src blob: *.facebook.com data:;block-all-mixed-content;upgrade-insecure-requests;report-uri https://www.facebook.com/csp/reporting/?m=c&minimize=0;
x-frame-options: DENY
strict-transport-security: max-age=15552000; preload
content-type: text/html; charset="utf-8"
x-fb-debug: M4/CJ5A2DSyEA2LjHGF5BfVjsjpbSZ/6GcXpeTlWMQ5//gvXD216nkTu5ISGgMpJ0Y1pKYBEgwXHJCKjyUx+hw==
date: Sat, 15 Jan 2022 16:25:09 GMT
priority: u=3,i
alt-svc: h3=":443"; ma=3600, h3-29=":443"; ma=3600
$ curl -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36" -s -D - https://www.twitter.com -o /dev/null
HTTP/2 200
date: Sat, 15 Jan 2022 16:25:30 GMT
expiry: Tue, 31 Mar 1981 05:00:00 GMT
pragma: no-cache
server: tsa_f
content-type: text/html; charset=utf-8
x-powered-by: Express
cache-control: no-cache, no-store, must-revalidate, pre-check=0, post-check=0
last-modified: Sat, 15 Jan 2022 16:25:30 GMT
x-frame-options: DENY
x-xss-protection: 0
x-content-type-options: nosniff
content-security-policy: connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api-stream.twitter.com https://ads-api.twitter.com https://aa.twitter.com https://caps.twitter.com https://media.riffsy.com https://pay.twitter.com https://sentry.io https://ton.twitter.com https://twitter.com https://upload.twitter.com https://www.google-analytics.com https://accounts.google.com/gsi/status https://accounts.google.com/gsi/log https://app.link https://api2.branch.io https://bnc.lt wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net ; default-src 'self'; form-action 'self' https://twitter.com https://*.twitter.com; font-src 'self' https://*.twimg.com; frame-src 'self' https://twitter.com https://mobile.twitter.com https://pay.twitter.com https://cards-frame.twitter.com https://accounts.google.com/ https://recaptcha.net/recaptcha/ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; img-src 'self' blob: data: https://*.cdn.twitter.com https://ton.twitter.com https://*.twimg.com https://analytics.twitter.com https://cm.g.doubleclick.net https://www.google-analytics.com https://www.periscope.tv https://www.pscp.tv https://media.riffsy.com https://*.giphy.com https://*.pscp.tv https://*.periscope.tv https://prod-periscope-profile.s3-us-west-2.amazonaws.com https://platform-lookaside.fbsbx.com https://scontent.xx.fbcdn.net https://scontent-sea1-1.xx.fbcdn.net https://*.googleusercontent.com https://imgix.revue.co; manifest-src 'self'; media-src 'self' blob: https://twitter.com https://*.twimg.com https://*.vine.co https://*.pscp.tv https://*.video.pscp.tv https://*.giphy.com https://media.riffsy.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net; object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com https://recaptcha.net/recaptcha/ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.google-analytics.com https://twitter.com https://app.link https://accounts.google.com/gsi/client https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js 'nonce-NDFlMzM0YjgtOWZkZS00MWFjLWE3ODktYjYxYmVjYjExMjlk'; style-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/style https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false
strict-transport-security: max-age=631138519
cross-origin-opener-policy: same-origin-allow-popups
cross-origin-embedder-policy: unsafe-none
x-response-time: 141
x-connection-hash: d29168d08eb4439a1e87f5d5234656e361f15325b079c5aaa156ea87b583d000
Github
$ curl -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36" -s -D - https://www.github.com -o /dev/null
HTTP/2 200
server: GitHub.com
date: Sat, 15 Jan 2022 16:25:45 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Accept-Language, Accept-Encoding, Accept, X-Requested-With
permissions-policy: interest-cohort=()
content-language: en-US
etag: W/"d4406bbb5b88163f272b94947d7b2fca"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
expect-ct: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
content-security-policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com objects-origin.githubusercontent.com www.githubstatus.com collector.githubapp.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com cdn.optimizely.com logx.optimizely.com/v1/events translator.github.com wss://alive.github.com github.githubassets.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src render.githubusercontent.com viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com secured-user-images.githubusercontent.com/ *.githubusercontent.com customer-stories-feed.github.com spotlights-feed.github.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ github.githubassets.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; worker-src github.com/assets-cdn/worker/ gist.github.com/assets-cdn/worker/
accept-ranges: bytes
x-github-request-id: 2B45:1FFB:1ED7F0B:203CC0F:61E2F58E
Best Practices
- Configuration proposal
- Prevent information disclosure via HTTP headers
- Prevent exposure to cross-site scripting when hosting uploaded files
- Quickly check security HTTP headers for applications exposed on the Internet
- Quickly check security HTTP headers for applications exposed internally
Configuration proposal
Please note the best practices below suggest methods to change webserver configuration to add headers. Security headers can also be successfully added to your application at the software level as well in almost every web language. Many web frameworks add some of these headers automatically.
The following section propose a configuration for the actively supported and working draft security headers.
Proposed values
⚠️ The Pragma
header is only specified for backwards compatibility with the HTTP/1.0 caches.
Header name | Proposed value |
---|---|
HTTP Strict Transport Security (HSTS) | max-age=31536000 ; includeSubDomains |
X-Frame-Options | deny |
X-Content-Type-Options | nosniff |
Content-Security-Policy | default-src 'self'; object-src 'none'; child-src 'self'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content |
X-Permitted-Cross-Domain-Policies | none |
Referrer-Policy | no-referrer |
Clear-Site-Data | "cache","cookies","storage" |
Cross-Origin-Embedder-Policy (COEP) | require-corp |
Cross-Origin-Opener-Policy (COOP) | same-origin |
Cross-Origin-Resource-Policy (CORP) | same-origin |
Permissions-Policy | accelerometer=(),autoplay=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(self),usb=(),web-share=(),xr-spatial-tracking=() |
Cache-Control | no-store, max-age=0 |
Pragma | no-cache |
Web server syntax
This section indicate the syntax to use to set a HTTP header according to the web server targeted.
Web server name | Syntax |
---|---|
Apache | Header always set [HEADER_NAME] [PROPOSED_VALUE] |
Nginx | add_header [HEADER_NAME] [PROPOSED_VALUE] always; |
Lighttpd | setenv.add-response-header = ("[HEADER_NAME]" => "[PROPOSED_VALUE]") |
IIS | Refer to this documentation. |
Quickly check security HTTP headers for applications exposed on the Internet
The online tool securityheaders.com can be used to achieve that objective.
It returns the grade in the following HTTP response headers:
- x-score: Contains a Base64 encoded JSON object with the grade letter and its associated color name.
- x-grade: Contains the grade letter.
$ curl -v "https://securityheaders.com/?hide=on&followRedirects=on&q=https://mozilla.org"
> Trying 104.21.70.128:443...
> Connected to securityheaders.com (104.21.70.128) port 443
> ...
< HTTP/2 200
< date: Tue, 02 Mar 2021 17:29:23 GMT
< content-type: text/html; charset=UTF-8
< vary: Accept-Encoding
< x-score: eyJzY29yZSI6IkEiLCAiY29sb3VyIjoiZ3JlZW4ifQ==
< x-grade: A
< ...
Content of the x-score header value:
$ echo eyJzY29yZSI6IkEiLCAiY29sb3VyIjoiZ3JlZW4ifQ== | base64 -d
{"score":"A", "colour":"green"}
Quickly check security HTTP headers for applications exposed internally
The portable cross-platform tool Venom with the dedicated test suites aligned with the OWASP Secure Headers Project can be used to achieve that objective.
Use the following set of commands:
# Get Venom binary file from
# https://github.com/ovh/venom/releases
# Get the YAML test suites from
# https://gist.github.com/righettod/f63548ebd96bed82269dcc3dfea27056
# Demonstration about usage available on
# https://gist.github.com/righettod/f63548ebd96bed82269dcc3dfea27056#gistcomment-3630811
$ venom run --var="target_site=https://mozilla.org" --var="logout_url=/logout" venom_security_headers_tests_suite.yml
• HTTP security response headers test suites (venom_security_headers_tests_suite.yml)
• Strict-Transport-Security SUCCESS
• X-Frame-Options SUCCESS
• X-Content-Type-Options SUCCESS
• Content-Security-Policy FAILURE
• X-Permitted-Cross-Domain-Policies SUCCESS
• Referrer-Policy SUCCESS
• Clear-Site-Data SUCCESS
• Cross-Origin-Embedder-Policy SUCCESS
• Cross-Origin-Opener-Policy SUCCESS
• Cross-Origin-Resource-Policy SUCCESS
• Permissions-Policy SUCCESS
• Cache-Control SUCCESS
• Feature-Policy SUCCESS
[info] This header was split into Permissions-Policy and Document-Policy and will be considered deprecated once all impacted features are moved off of feature policy. (venom_security_headers_tests_suite.yml:152)
• Public-Key-Pins SUCCESS
[info] This header has been deprecated by all major browsers and is no longer recommended. Avoid using it, and update existing code if possible! (venom_security_headers_tests_suite.yml:164)
• Expect-CT SUCCESS
[info] This header will likely become obsolete in June 2021. Since May 2018 new certificates are expected to support SCTs by default. Certificates before March 2018 were allowed to have a lifetime of 39 months, those will all be expired in June 2021. (venom_security_headers_tests_suite.yml:175)
• X-Xss-Protection SUCCESS
[info] The X-XSS-Protection header has been deprecated by modern browsers and its use can introduce additional security issues on the client side. (venom_security_headers_tests_suite.yml:189)
• SecurityHeaders-Rating SKIPPED
Prevent information disclosure via HTTP headers
This section provides a collection of HTTP response headers to remove, when possible, from any HTTP response to prevent any disclosure of technical information about environment. The following list of headers can be used to configure a reverse proxy or a web application firewall to handle removal operation of the mentioned headers.
Header name | Header value example | Description |
---|---|---|
Server | Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips |
Contain information about the server handling the request. |
Liferay-Portal | Liferay Digital Experience Platform 7.2.10 GA1 |
Contain the version of the Liferay software in use. |
X-Turbo-Charged-By | LiteSpeed/5.4.12 Enterprise |
Contain information about the server handling the request. |
X-Powered-By | PHP/5.3.3 |
Contain information about hosting environments or other frameworks in use. |
X-Server-Powered-By | Engintron |
Contain information about hosting environments or other frameworks in use. |
X-Powered-CMS | Bitrix Site Manager (DEMO) |
Contain the information about the CMS that generated the HTTP response. |
SourceMap or X-SourceMap | https://mysite.com/js/mylib.js.map |
Links generated code to a source map file, enabling the browser to reconstruct the original source and present the reconstructed original in the debugger. |
X-AspNetMvc-Version | 5.2 |
Contain the version of the ASP .Net MVC framework in use. |
X-AspNet-Version | 4.0.30319 |
Contain the version of the ASP .Net framework in use. |
X-SourceFiles | =?UTF-8?B?QzpcVXNlcnN?= |
Contain information needed by the .Net SDK debugger during debugging operation on a project. |
X-Redirect-By | TYPO3 Shortcut/Mountpoint |
Specifies the component that is responsible for a particular redirect (source Wikipedia). |
X-Generator | Drupal 8 |
Contain the information about the CMS that generated the HTTP response. |
X-Generated-By | Smartsite version 7.11.1.3 |
Contain the information about the CMS that generated the HTTP response. |
X-CMS | Thinq CMS 1.7.0.0 |
Contain the information about the CMS that generated the HTTP response. |
Prevent exposure to cross-site scripting when hosting uploaded files
This section describes, how the HTTP response header named Content-Disposition, can be used to prevent exposure to cross-site scripting when hosting uploaded files and opening them in the same web browsing context than the application.
It can happen a case in which an application allows a user to upload a file and then allow this file to be accessed by other users. If such feature allows uploading of HTML files (also apply for SVG file) then it can be used, as a vector, to store an HTML file containing JavaScript code. Therefore, the feature become prone to stored cross-site scripting vulnerability.
To prevent this exposure, the HTTP response header named Content-Disposition, can be used with the following value to instruct browsers to download the file instead of open it in the same web browsing context than the application:
Content-Disposition: attachment; filename="myfile.html"
Miscellaneous
This section provide extra useful information about HTTP Security headers.
Request headers
Fetch metadata request header
A fetch metadata request header is an HTTP request header that provides additional information about the context from which the request originated. This allows the server to make decisions about whether a request should be allowed based on where the request came from and how the resource will be used .
These headers are prefixed with Sec-
, and hence have forbidden header names. As such, they cannot be modified from JavaScript.
Source Mozilla MDN.
These headers can be leveraged to add protection measures against XS-Leaks attacks.
Sec-Fetch-Dest
The Sec-Fetch-Dest
fetch metadata request header indicates the request’s destination. That is the initiator of the original fetch request, which is where (and how) the fetched data will be used.
Possible values are detailled here.
Source Mozilla MDN.
Sec-Fetch-Mode
The Sec-Fetch-Mode
fetch metadata request header indicates the mode of the request: cors, no-cors, same-origin, navigate or websocket.
Broadly speaking, this allows a server to distinguish between: requests originating from a user navigating between HTML pages, and requests to load images and other resources.
Possible values are detailled here.
Source Mozilla MDN.
Sec-Fetch-User
The Sec-Fetch-User
fetch metadata request header is only sent for requests initiated by user activation, and its value will always be ?1
.
Source Mozilla MDN.
Sec-Fetch-Site
The Sec-Fetch-Site
fetch metadata request header indicates the relationship between a request initiator’s origin and the origin of the requested resource.
In other words, this header tells a server whether a request for a resource is coming from the same origin, the same site, a different site, or is a “user initiated” request. The server can then use this information to decide if the request should be allowed.
Possible values are detailled here.
Source Mozilla MDN.
Explanation about Site vs Origin can be found here.
Example
GET /www-project-secure-headers/
Host: owasp.org
User-Agent: Chrome/91.0.4472.124
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Sec-Fetch-User: ?1
References
- https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header
- https://caniuse.com/mdn-http_headers_sec-fetch-dest
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Dest
- https://caniuse.com/mdn-http_headers_sec-fetch-mode
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Mode
- https://caniuse.com/mdn-http_headers_sec-fetch-user
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-User
- https://caniuse.com/mdn-http_headers_sec-fetch-site
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Site
- https://web.dev/same-site-same-origin/
- https://jub0bs.com/posts/2021-01-29-great-samesite-confusion/#are-site-and-origin-interchangeable
- https://portswigger.net/daily-swig/firefox-becomes-latest-browser-to-support-fetch-metadata-request-headers
- https://xsleaks.dev/docs/defenses/opt-in/fetch-metadata/
Entity referencing the OWASP Secure Headers Project
Feel free to contact project leaders if your company or software (open source or not) was using the project.
Company
- Cloud.gov.
- Amazon AWS.
- Salesforce.
- Black Hills Information Security.
- Progress.
- Bloomreach.
- CrashTest Security.
Software
- Nmap.