OWASP Secure Headers Project

Introduction

OSHP Logo

OWASP Production External Links Validity Check Update headers reference JSON files Update monitoring technical references dashboard Perform_monitoring_oshp_site_references

🎯 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.

🏭 All the tools provided by the OSHP are gathered under this GitHub organization.

πŸ“Ί A presentation of the project is available on the following locations:

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:

Security headers usage validator

βœ… We provide a venom tests suite to validate an HTTP security response header configuration against OWASP Secure Headers Project recommendation:

πŸ§ͺ We also provide a online mock endpoint returning an HTTP response, for which, all HTTP response headers recommended by the OSHP will be set:

  • It is automatically deployed on https://oshp-validator-mock.onrender.com
  • Technical details about this endpoint are here.

Security headers reference files

πŸ“– As mentioned in previous sections, we provide the collection of HTTP response security headers to add as well as HTTP response headers to remove, both in table form.

πŸ’‘ Additionally, we provide this information as two JSON files to enable automation in the context of a provisioning workflow:

πŸ“‘ These json files are automatically updated.

Technical references health dashboard

πŸ“ We automatically generate and monitor this dashboard to identify any dead project referenced in the Technical Resources tab.

Discussions, information and roadmap

πŸ’¬ We use the GitHub discussions feature for discussions about the project as well as spreading global information about it.

πŸ‘©β€πŸ’» The work on the OSHP projects and associated components is tracked using the GitHub project feature.

πŸ“– This is documented into the Case Studies tab.

Contributors

πŸ’Œ Contributors to OSHP, before the migration of the project to GitHub:

πŸ’Œ Visit this page for updated information about the contributors since the migration of the project to GitHub.

Licensing

πŸ“‘ This project content is free to use. It is licensed under the Apache 2.0 License.


Response Headers

πŸ’‘ The collection of HTTP response security headers mentioned in this section is applicable when the user agent processing the HTTP response is a browser. The support for these headers by non-browser API clients (user agent), like for example an HTTP client in a programming language, is not standardized. So, it requires specific testing to identify if an HTTP response security header is supported or not by such HTTP client.

🚦 Header lifecycle flow:

Header lifecycle flow

πŸ“ Working draft

βœ… Active

⏰ Almost deprecated

None

❌ Deprecated

Strict-Transport-Security

HTTP Strict Transport Security (also named HSTS) is a browser 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 within a defined timespan (max-age) not via the clear text HTTP protocol. HSTS is an IETF standard 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).

πŸ“ Important note about the behavior of the header over a HTTP connection (source Mozilla MDN):

  • The Strict-Transport-Security header is ignored by the browser when your site has only been accessed using HTTP.
  • Once your site is accessed over HTTPS with no certificate errors, the browser knows your site is HTTPS capable and will honor the Strict-Transport-Security header.

πŸ’‘ If you need to let the access open, via HTTP, to the web server but want to ensure that Strict-Transport-Security header is taken into account for your site then you can use the preload directive.

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.
preload If this optional parameter is specified, its instruct the browser to always access the site using HTTPS because the site is included into Strict-Transport-Security preload list.

Example

Strict-Transport-Security: max-age=31536000
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
Strict-Transport-Security: max-age=31536000 ; includeSubDomains ; preload

References

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

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

Content-Security-Policy

A Content Security Policy (also named CSP) requires careful tuning and testing after definition of the policy. A content security policy can have significant impact on the way browsers render pages (e.g., inline JavaScript or CSS can disabled). A proper CSP can prevents a wide range of attacks, including cross-site scripting, other cross-site injections and click jacking.

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. Useful against click jacking
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 using HTTPS when trying to download insecure HTTP resources
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

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

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

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

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).

πŸ’‘ To fully understand where CORP and COEP work:

  • CORP applies on the loaded resource side (resource owner).
  • COEP applies on the β€œloader” of the resource side (consumer of the resource).

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

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).

πŸ’‘ To fully understand where CORP and COEP work:

  • CORP applies on the loaded resource side (resource owner).
  • COEP applies on the β€œloader” of the resource side (consumer of the resource).

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

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

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

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

🧭 As the specification is still under development, it is better to consult this page to obtain the current list of supported directives.

Example

Permissions-Policy: accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),display-capture=(),document-domain=(),encrypted-media=(),fullscreen=(),gamepad=(),geolocation=(),gyroscope=(),layout-animations=(self),legacy-image-formats=(self),magnetometer=(),microphone=(),midi=(),oversized-images=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),speaker-selection=(),sync-xhr=(self),unoptimized-images=(self),unsized-media=(self),usb=(),screen-wake-lock=(),web-share=(),xr-spatial-tracking=()

References

Feature-Policy

Deprecated: Replaced by the header Permissions-Policy.

Feature Policy allows web developers to selectively enable, disable, and modify the behavior of certain features and APIs in the browser. It is similar to Content Security Policy but controls features instead of security behavior (Source Mozilla MDN).

Values

Refer to this page to obtains the list of supported directives.

Example

Feature-Policy: vibrate 'none'; geolocation 'none'

References

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

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

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 use Content-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

Pragma

Deprecated.

The Pragma HTTP/1.0 general header is an implementation-specific header that may have various effects along the request-response chain.

This header serves for backwards compatibility with the HTTP/1.0 caches that do not have a Cache-Control HTTP/1.1 header (source Mozilla MDN).

Values

Value Description
no-cache Same as Cache-Control: no-cache. Forces caches to submit the request to the origin server for validation before a cached copy is released.

Example

Pragma: no-cache

References


Browser Support

πŸ“š A reference is provided, for each header, to a site always providing up-to-date information.

Feature Reference
HTTP Strict Transport Security (HSTS) https://caniuse.com/stricttransportsecurity
X-Frame-Options https://caniuse.com/x-frame-options
X-Content-Type-Options https://caniuse.com/mdn-http_headers_x-content-type-options
Content-Security-Policy https://caniuse.com/?search=content-security-policy
X-Permitted-Cross-Domain-Policies https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/xdomain.html
Referrer-Policy https://caniuse.com/referrer-policy
Feature-Policy https://caniuse.com/feature-policy
HTTP Public-Key-Pins (HPKP) https://caniuse.com/publickeypinning
Expect-CT https://caniuse.com/mdn-http_headers_expect-ct
X-XSS-Protection https://caniuse.com/mdn-http_headers_x-xss-protection
Clear-Site-Data https://caniuse.com/?search=Clear-Site-Data
Cross-Origin-Embedder-Policy (COEP) https://caniuse.com/mdn-http_headers_cross-origin-embedder-policy
Cross-Origin-Opener-Policy (COOP) https://caniuse.com/mdn-http_headers_cross-origin-opener-policy
Cross-Origin-Resource-Policy (CORP) https://caniuse.com/mdn-http_headers_cross-origin-resource-policy
Permissions Policy https://caniuse.com/permissions-policy
Cache-Control https://caniuse.com/mdn-http_headers_cache-control
Pragma https://caniuse.com/mdn-http_headers_pragma

Best Practices

Configuration proposal

Please note the best practices below suggest methods to change web server 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 proposes a configuration for the actively supported and working draft security headers.

πŸ’‘ Additional information about HTTP security headers on OpenCRE.

πŸ“– The headers proposed below can be applied both in the context of a classic web application and in that of a web API.

🚩 The header Clear-Site-Data will cause the browser to take additional processing time for the HTTP response, so, set it to the logout function when possible.

πŸ”¬ For the header Permissions-Policy, as it is currently only supported by Chromium based browsers, the proposed value was generated with this site and tested against the version 128.0.6606.0 of Chromium to only specify supported features.

πŸ’‘ Content of the table below is also provided, as JSON, via this file (automatically updated).

Header name Proposed value
Strict-Transport-Security max-age=31536000; includeSubDomains
X-Frame-Options deny
X-Content-Type-Options nosniff
Content-Security-Policy default-src 'self'; form-action 'self'; object-src 'none'; 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 require-corp
Cross-Origin-Opener-Policy same-origin
Cross-Origin-Resource-Policy same-origin
Permissions-Policy accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(self), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), unload=()
Cache-Control no-store, max-age=0

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.

πŸ’‘ Additional information about technical information disclosure in HTTP header on OpenCRE.

πŸ’‘ When an HTTP response header is known by the analytics site WebTechSurvey, then, a reference link is added to its usage statistics page. Otherwise, a reference link regarding the documentation of the header is provided.

🚩 The response header Content-Type can sometimes discloses the web framework used. It is the case for the following ones:

πŸ’‘ Content of the table below is also provided, as JSON, via this file (automatically updated).

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 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-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.
X-Powered-By-Plesk PleskLin or PleskWin Indicate that the platform is based on the Plesk software in addition to the underlying operating system.
X-Php-Version 7.4 Indicate the version of PHP technology used.
Powered-By PrestaShop Indicate the name of the framework or platform used.
X-Content-Encoded-By Joomla! 2.5 Indicate the name of the framework or platform used.
Product Z-BlogPHP 1.7.2 Indicate the name of the framework or platform used.
X-CF-Powered-By CF-Joomla 0.1.5 Indicate the name of the framework or platform used.
X-Framework JP/4.01 Indicate the name of the framework or platform used.
Host-Header owasp.org Indicate which virtual host of the web server the response is coming from.
Pega-Host srv-pega11 Indicate the internal host name of the server that handled the request in the context of usage of a software from the PEGA company.
X-Atmosphere-first-request true Indicate that the java framework Atmosphere is used.
X-Atmosphere-tracking-id 7852fcbf-f8a9-4667-9dcc-a0b5b162499c Indicate that the java framework Atmosphere is used.
X-Atmosphere-error Websocket protocol not supported Indicate that the java framework Atmosphere is used.
X-Mod-Pagespeed 1.13.35.2-0 Indicate the presence of the Apache module mod_pagespeed in the call flow.
X-Page-Speed 1.13.35.2-0 Indicate the presence of the Nginx module mod_pagespeed in the call flow.
X-Varnish-Backend pb01 Indicate the name of the backend server from which the Varnish instance will accelerate the content.
X-Varnish-Server proxy01 Indicate the name of the Varnish server instance that provided the accelerated content.
X-Envoy-Upstream-Service-Time 42 Indicate the presence of the proxy software Envoy in the call flow.
X-Envoy-Attempt-Count 1 Indicate the presence of the proxy software Envoy in the call flow.
X-Envoy-External-Address 124.128.159.165 Indicate the presence of the proxy software Envoy in the call flow.
X-Envoy-Internal true Indicate the presence of the proxy software Envoy in the call flow.
X-Envoy-Original-Dst-Host 10.195.16.237:8888 Indicate the presence of the proxy software Envoy in the call flow.
X-B3-ParentSpanId dea3f6d0324583db Indicate the presence of the software Zipkin that is a distributed tracing system.
X-B3-Sampled 0 Indicate the presence of the software Zipkin that is a distributed tracing system.
X-B3-SpanId 244753d494e83353 Indicate the presence of the software Zipkin that is a distributed tracing system.
X-B3-TraceId 11bef07b0f5c0468 Indicate the presence of the software Zipkin that is a distributed tracing system.
K-Proxy-Request activator Indicate the presence of the software Knative that is an Open-Source Enterprise-level solution to build Serverless and Event Driven Applications in Kubernetes environments.
X-Old-Content-Length 135 Indicate the presence of the software WebSEAL that is a high performance, multithreaded web server by IBM.
$wsep empty value Indicate the presence of the software WebSphere Application Server that is a JavaEE application server by IBM.
X-Nextjs-Matched-Path /blog Indicate that the web framework Next.js is used.
X-Nextjs-Page /articles Indicate that the web framework Next.js is used.
X-Nextjs-Cache REVALIDATED Indicate that the web framework Next.js is used.
X-Nextjs-Redirect /home Indicate that the web framework Next.js is used.
X-OneAgent-JS-Injection true Indicate that the Dynatrace analytics and automation platform is used.
X-ruxit-JS-Agent true Indicate that the Dynatrace analytics and automation platform is used.
X-dtHealthCheck Technical diagnostic data Indicate that the Dynatrace analytics and automation platform is used.
X-dtAgentId 95b3121c36 Indicate that the Dynatrace analytics and automation platform is used.
X-dtInjectedServlet com.company.ReportServlet Indicate that the Dynatrace analytics and automation platform is used.
X-Litespeed-Cache-Control no-cache Indicate the presence of the LiteSpeed web server.
X-LiteSpeed-Purge /phpinfo.php Indicate the presence of the LiteSpeed web server.
X-LiteSpeed-Tag pubtag1,pubtag2 Indicate the presence of the LiteSpeed web server.
X-LiteSpeed-Vary value=ismobile Indicate the presence of the LiteSpeed web server.
X-LiteSpeed-Cache hit,litemage Indicate the presence of the LiteSpeed web server.
X-Umbraco-Version 4.7 Indicate the usage of the Umbraco CMS software as well as its version.
OracleCommerceCloud-Version 23.08.01 Indicate the usage of the Oracle Commerce software as well as its version.
X-BEServer EXSRV01 Indicate the internal host name of the server that handled the request in the context of usage of the Microsoft Exchange software.
X-DiagInfo EXSRV01 Indicate the internal host name of the server that handled the request in the context of usage of the Microsoft Exchange software.
X-FEServer EXSRV01 Indicate the internal host name of the server that handled the request in the context of usage of the Microsoft Exchange software.
X-CalculatedBETarget exsrv01.mydomain.com Indicate the internal host name of the server that handled the request in the context of usage of the Microsoft Exchange software.
X-OWA-Version 15.2.1258.27 Indicate the version of the Microsoft Exchange software in use.
X-Cocoon-Version 2.1.13 Indicate that the web framework Apache Cocoon is used as well as the version used.
X-Kubernetes-PF-FlowSchema-UI cf931e2d-5a5e-4c12-892c-9bafa71f30dc Indicate that the web application issuing the HTTP response is deployed on a Kubernetes cluster.
X-Kubernetes-PF-PriorityLevel-UID 78b3face-e1cf-4fc6-a27e-08eb7f0f5b23 Indicate that the web application issuing the HTTP response is deployed on a Kubernetes cluster.
X-Jitsi-Release 5082 Indicate the version of Jitsi software in use.
X-Joomla-Version 3.9.25 Indicate that the CMS Joomla is used as well as the version used.
X-Backside-Transport OK OK Indicate the presence of the products IBM WebSphere DataPower in the call flow.

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"

Prevent CORS misconfiguration issues

πŸ“– An excellent tutorial about Cross-Origin Resource Sharing (called CORS) is provided on the Mozilla MDN. In addition, Julien Cretel provided a great blog post about CORS pitfalls.

This section proposes an approach to help preventing CORS misconfiguration issues using a simple idea: Provide the collection of CORS related HTTP response headers to use according to different contexts.

Key points to consider

  • πŸ’‘ If the web framework/web server you are using provides CORS features then always leverage them instead of implements it manually:
  • 🚩 Whatever the context, when the request is a HTTP OPTIONS (preflight request) then the value provided by the following headers must be validated against expected values. If the validation failed then return an HTTP 403 without any CORS related HTTP response headers:

  • 🚩 Validation of the Origin / Access-Control-Request-Method / Access-Control-Request-Headers request header value, against a list of allowed ones, must be performed using strict case sensitive string comparison to prevent, as much as possible, the presence of bypasses into the validation logic. If possible, does not use regular expression for the implementation of the validation, see here for an explanation of the source of this recommendation.

  • 🚩 CORS scope is the access control aspect, from a browser perspective (client side), regarding cross origins access to a resource. Thus, it does NOT replace the requirement to implements access control on the server side too. CORS and server-side access controls are complementary.

  • 🚩 Never take the value of the request header Origin to add it into the response header Access-Control-Allow-Origin (mirroring), see here for an explanation of the source of this recommendation. Indeed, always use a list of allowed origins when only a restricted collection of origins is expected to call your endpoints.

Contexts

Public without authentication

πŸ’¬ Context:

Your endpoints are expected to be consumed, by a browser, from any origins without any authentication.

πŸ’» Configuration proposal:

Access-Control-Allow-Origin: *
Access-Control-Max-Age: 3600
Access-Control-Allow-Credentials: false

Public with authentication

πŸ’¬ Context:

Your endpoints are expected to be consumed, by a browser, from any origins with authentication.

🚩 The value *, for the response header Access-Control-Allow-Origin, cannot be used when the response header Access-Control-Allow-Credentials is allowed (true). Indeed, the browser raises the following error (tested on Chrome 118.x):

The value of the 'Access-Control-Allow-Origin' header in the response must not be 
the wildcard '*' when the request's credentials mode is 'include'.

πŸ“– It is explicitly mentioned, into the Mozilla MDN documentation, as the following:

When responding to a "credentialed request" request, the server must specify an origin in the value 
of the Access-Control-Allow-Origin header, instead of specifying the "*" wildcard.

Therefore, refer to the restricted with authentication case for the configuration to use.

Restricted without authentication

πŸ’¬ Context:

Your endpoints are expected to be consumed, by a browser, from a specific collection of origins without any authentication.

πŸ’» Configuration proposal:

  • If the value of the request header Origin is present into the list of allowed Origins then:
Access-Control-Allow-Origin: [Value_Taken_From_The_List_Of_Allowed_Origins]
Access-Control-Max-Age: 10
Access-Control-Allow-Credentials: false

Restricted with authentication

πŸ’¬ Context:

Your endpoints are expected to be consumed, by a browser, from a specific collection of origins with authentication.

πŸ’» Configuration proposal:

  • If the value of the request header Origin is present into the list of allowed Origins then:
Access-Control-Allow-Origin: [Value_Taken_From_The_List_Of_Allowed_Origins]
Access-Control-Max-Age: 10
Access-Control-Allow-Credentials: true

Test CORS configuration

The tools nuclei can be used, via the template named cors-misconfig, to test a CORS configuration.

πŸ’» Command to use:

$ nuclei -silent -template-id cors-misconfig -u https://domain.com
[cors-misconfig:arbitrary-origin] [http] [info] https://domain.com [...]

References

Prevent information disclosure via the browser local cached files

This section describes why it is important to specify a caching policy, via the Cache-Control HTTP response header, when sensitive information is managed by a web-based application.

Context

πŸ’¬ The application allows a user to access to documents containing information, considered sensitive, from a confidentiality perspective.

Let’s assume that the application returns the following HTTP response to a request, in which, no caching policy is defined:

HTTP/1.1 200 OK
accept-ranges: bytes
content-length: 433994
content-type: application/pdf
date: Sat, 30 Mar 2024 10:06:34 GMT
server: LiteSpeed

So, the browser will store a copy of the file (here a PDF one) into its cache storage for a certain amount of time.

🚩 Consequence: Any application running on the user’s computer, will be able to access to the file (at least if executed as the user identity or an administrator one) causing an exposure of the resource to non-expected entities.

πŸ“Ί This demonstration video show an example, of such information disclosure, via a file cached by the browser.

Configuration proposal

πŸ’» To prevent such issue, the following caching policy can be specified:

Cache-Control: no-store, max-age=0

πŸ‘€ Where:

  • no-store: Is used to indicate that the response may not be stored in any cache.
  • max-age=0: Is used to force the expiration of any cached version of the resources associated to the response.

πŸ’‘ The HTTP response header Clear-Site-Data can also be leveraged, in addition, to instruct the browser to remove any cached data related to the application.

πŸ“– An excellent research and course content, about web cache poisoning, is provided by the PortSwigger team.

References

Prevent CSP bypasses

This section describes some points, to keep in mind, during the creation of a Content-Security-Policy (called CSP) policy to prevent introducing bypasses.

🚩 Not every directives fallback to the default-src directive when it is not specified in the CSP policy.

Directive form-action

πŸ‘€ It is the case for the form-action directive. Therefore, an html form can be used to bypass the CSP in place when the form-action is not defined.

πŸ“Ί This demonstration video show an example.

πŸ’‘ Therefore, ensure to always specify the form-action directive in a CSP policy to at least, the 'self' value, to allow forms only on the current domain.

Directive frame-ancestors

πŸ‘€ It is the case for the frame-ancestors directive. Therefore, IF it is not defined AND IF the header X-Frame-Options is not/incorrectly specified then the current domain can be embedded into a frame.

πŸ“Ί This demonstration video show an example.

πŸ’‘ Therefore, ensure to always specify the frame-ancestors directive in a CSP policy to at least, the 'none' value, to deny the current domain to be β€œframed”.

Support for a large CSP policy

Tests were performed to identify if any limitation was in place, regarding the definition and usage of a large CSP policy. Tests were performed against the following browsers:

  • Firefox 132.0.2.
  • Chromium 131.0.6755.0.
  • Edge 131.0.2903.51.

πŸ’‘ Based on tests performed, modern browsers supports a sufficient size to specify a large CSP policy in case of need.

πŸ“Š Technical details can be found here (backup copy).


Technical Resources

πŸ“š This section provides a list of tools as well as documents to understand, analyze, develop and administer HTTP secure headers to help achieving more secure and trustworthy web systems.

Presentations

Analysis Tools

Tool Description Ref
hsecscan A security scanner for HTTP response headers. πŸ‘©β€πŸ’»
humble A humble, and fast, security-oriented HTTP headers analyzer. πŸ‘©β€πŸ’»
Mozilla Observatory A Mozilla project designed to help developers, system administrators, and security professionals configure their sites safely and securely. 🌎 / πŸ‘©β€πŸ’» / πŸ‘©β€πŸ’»
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. πŸ‘©β€πŸ’»
DrHEADer DrHEADer helps with the audit of security headers received in response to a single request or a list of requests. πŸ‘©β€πŸ’»
csp-evaluator NPM module allowing developers and security experts to check if a Content Security Policy serves as a strong mitigation against XSS attacks. πŸ‘©β€πŸ’»

Development Libraries

Java

Library Description Ref
Spring Security Spring Security’s support for adding various security headers to the response. 🌎

DotNet

Library Description Ref
NWebsec NWebsec consists of several security libraries for ASP.NET applications. 🌎
NetEscapades.AspNetCore.SecurityHeaders Small package to allow adding security headers to ASP.NET Core websites. πŸ‘©β€πŸ’»
OwaspHeaders.Core .NET Core middleware for injecting the OWASP recommended HTTP Headers for increased security πŸ‘©β€πŸ’»

Ruby

Library Description Ref
secure_headers Security related headers all in one gem. πŸ‘©β€πŸ’»

PHP

Library Description Ref
SecureHeaders A PHP class aiming to make the use of browser security features more accessible. πŸ‘©β€πŸ’»
secure-headers PHP Secure Headers for Laravel and non-Laravel projects. πŸ‘©β€πŸ’»

NodeJS

Library Description Ref
helmet Module to help secure Express apps with various HTTP headers. πŸ‘©β€πŸ’»
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. πŸ‘©β€πŸ’»
blankie A CSP plugin for hapi. πŸ‘©β€πŸ’»

Python

Library Description Ref
django-csp and django-security Content Security Policy for Django. A collection of models, views, middlewares, and forms to help secure a Django project. πŸ‘©β€πŸ’» / πŸ‘©β€πŸ’»
Secweb Secweb is a pack of security middlewares for fastApi and starlette server it includes CSP, HSTS, and many more. πŸ‘©β€πŸ’»
secure Lightweight library to add security headers to Django, Flask, FastAPI, and more. πŸ‘©β€πŸ’»

Go

Library Description Ref
secure HTTP middleware for Go that facilitates some quick security wins. πŸ‘©β€πŸ’»

Rust

Library Description Ref
owasp-headers Best-practice OWASP HTTP response headers for Rust. 🌎

Code Snippets

🧾 The following code collection provides various code snippets to make working with HTTP security headers easier.

Convert a Permissions-Policy back to Feature-Policy

As the Permissions-Policy header is still in development and is not yet well supported, it can be interesting to use the two formats to increase the coverage of browsers according to their support level for Permissions-Policy and Feature-Policy policy headers.

The following python3 code snippet can be useful to achieve such conversion.

πŸ“‘ Source for the conversion rules was this one.

πŸ’» Code snippet:

permissions_policy = 'fullscreen=(), geolocation=(self "https://game.com" "https://map.example.com"), gyroscope=(self), usb=*'
feature_policy_directives = []
# Collect directives
permissions_policy_directives = permissions_policy.split(",")
# Process each directive
for permissions_policy_directive in permissions_policy_directives:
    # Remove leading and trailing spaces
    directive = permissions_policy_directive.strip(" ")
    # Remove all double quotes
    directive = directive.replace("\"", "")
    # Replace disabling expression () by the corresponding one in Feature-Policy
    directive = directive.replace("()", "'none'")
    # Quote keywords: self
    directive = directive.replace("self", "'self'")
    # Replace the equals affectation character by a space
    directive = directive.replace("=", " ")
    # Remove parenthesis
    directive = directive.replace("(", "").replace(")", "")
    # Add the current directive to the collection
    feature_policy_directives.append(directive)
# Convert the collection of directives to a string with ; as directives separator
feature_policy = "; ".join(feature_policy_directives)
print(feature_policy)

πŸ’» Execution example:

$ python code.py
fullscreen 'none'; geolocation 'self' https://game.com https://map.example.com; gyroscope 'self'; usb *

Test locally a Content-Security-Policy for weaknesses

It can be interesting to validate locally a Content-Security-Policy for presence of weaknesses prior to apply it on deployed web applications.

The following JavaScript code snippet can be useful to achieve such validation by leveraging the csp-evaluator NPM module provided by Google.

πŸ’» Code snippet:

import {CspEvaluator} from "csp_evaluator/dist/evaluator.js";
import {CspParser} from "csp_evaluator/dist/parser.js";

const args = process.argv.slice(2)
if(args.length == 0){
    console.error("[!] Missing CSP!");
}else{
    const csp = args[0]
    console.info(`[+] CSP to evaluate:\n${csp}`);
    const parsed = new CspParser(csp).csp;
    console.info(`[+] Evaluation results:`);
    const results = new CspEvaluator(parsed).evaluate();
    results.forEach(elt => {
        let info = `[Directive '${elt.directive}' - Severity ${elt.severity}]: ${elt.description}`;
        console.info(info);
    });
}

πŸ’» Execution example:

$ node code.js "default-src 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content"
[+] CSP to evaluate:
default-src 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content
[+] Evaluation results:
[Directive 'default-src' - Severity 50]: 'self' can be problematic if you host JSONP, Angular or user uploaded files.

Generate configuration code using the OSHP headers reference files

The following bash code snippet, leveraging jq, can be used to generate configuration code using the OSHP headers reference files.

πŸ’» Code snippet and execution example:

# Generate the Nginx collection of instructions to add the recommended HTTP response headers
$ curl -sk https://owasp.org/www-project-secure-headers/ci/headers_add.json | jq -r '.headers[] | "add_header \(.name) \(.value);"'
add_header Cache-Control no-store, max-age=0;
add_header Clear-Site-Data "cache","cookies","storage";
add_header Cross-Origin-Embedder-Policy require-corp;
...

Quickly check security HTTP headers

The portable cross-platform tool Venom with the dedicated OSHP Validator test suites aligned with the OWASP Secure Headers Project can be used.

πŸ’» Use the following example set of commands:

$ venom run --var="target_site=https://mozilla.org" --var="logout_url=/logout" tests_suite.yml
β€’ HTTP security response headers test suites
    β€’ 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.
    β€’ 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!
    β€’ 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.
    β€’ 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.

Syntax for adding HTTP response headers on different web servers

Apache

πŸ’» Directive:

Header always set [HEADER_NAME] [PROPOSED_VALUE]

🌎 References:

Nginx

πŸ’» Directive:

add_header [HEADER_NAME] [PROPOSED_VALUE] always;

🌎 References:

Lighttpd

πŸ’» Directive:

setenv.add-response-header = ("[HEADER_NAME]" => "[PROPOSED_VALUE]")

🌎 References:

IIS

πŸ’» Directive:

<add name="[HEADER_NAME]" value="[PROPOSED_VALUE]" />

🌎 References:


Miscellaneous

πŸ’‘ This section provides extra useful information about HTTP Security headers.

Request headers

Private Network Access request header

Description

The Private Network Access specification provides a feature allowing an application, located on a private address, to identify if the incoming HTTP request was sent from an application located on a public address.

🎯 The objective is to prevent attack, in which, a page hosted on a public network like, the Internet network, try to send a request to an application hosted on a private network:

PNA schema

πŸ“‘ Source of the schema.

Example

πŸ’» Code of a page hosted on Internet on https://example.com/page.html:

<!DOCTYPE html>
<html>
<header>
    <title>Evil App</title>
</header>
<body>
    <!-- 
        We try to load an image from the router
        deployed on the local private network.
    -->
    <img src="https://router.local/icon.svg">
</body>
</html>

πŸ’» Request sent by the browser when the page is loaded (tested on Chrome 116.x):

OPTIONS /icon.svg HTTP/1.1
Host: router.local
User-Agent: Chrome/116.0.0.0 Safari/537.36
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en-GB;q=0.9,en;q=0.8
Access-Control-Request-Method: GET
Access-Control-Request-Private-Network: true
Connection: keep-alive
Origin: https://example.com
Referer: https://example.com
Sec-Fetch-Dest: image
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site

πŸ’¬ The browser sent a CORS preflight request to notify the application, located on the private network, about the cross-network request that the application, located on the public network, want to perform.

πŸ’‘ Note the special request header: Access-Control-Request-Private-Network: true

🀝 If the application on the private network, wants to allow the request, then it will return the following CORS headers that will make the preflight successful:

πŸ’‘ Note the special response header: Access-Control-Allow-Private-Network: true

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Allow-Private-Network: true
...

πŸ“ To summarize, the application on the private network, uses its response to the preflight request to allow or not the real request to be performed:

  • βœ… Preflight succeed: The browser will send the real request (HTTP GET in our example).
  • ❌ Preflight fail: The browser will NOT send the real request.

References

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 detailed 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 detailed 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 detailed 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


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

Google

$ 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

Facebook

$ 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

Twitter

$ 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

Case Studies

πŸ“‹ This section list the entities referencing the OWASP Secure Headers Project.

πŸ“© Feel free to contact project leaders if your company or software (open source or not) was using the OSHP project.

πŸ”Ž Google dork used to identity references was allintext:"OWASP Secure Headers Project" -site:owasp.org -site:github.com -site:youtube.com -site:twitter.com -site:linkedin.com.

🌎 Use the following absolute URL syntax to create a reference link to a specific location of the OSHP site. The presence of the index.html file is mandatory otherwise any anchor specified is not effective:

https://owasp.org/www-project-secure-headers/index.html#[TAB-ID]_[HEADER-ID-INSIDE-TAB]

πŸ’‘ Where:

  • [TAB-ID]: ID of the tab that can be obtained with the link to it.
  • [HEADER-ID-INSIDE-TAB]: Href value of the link to the section inside the tab.

πŸ‘€ Example of reference link to the section about the header Clear-Site-Data in the Response Headers tab:

https://owasp.org/www-project-secure-headers/index.html#div-headers_clear-site-data

πŸ‘€ Example of reference link to the section PHP in the Technical Resources tab:

https://owasp.org/www-project-secure-headers/index.html#div-technical_php

Software