title | displaytext | layout | tab | order | tags |
---|---|---|---|---|---|
bestpractices |
Best Practices |
true |
3 |
headers |
- Configuration proposal
- Prevent information disclosure via HTTP headers
- Prevent exposure to cross-site scripting when hosting uploaded files
- Prevent CORS misconfiguration issues
- Prevent information disclosure via the browser local cached files
- Prevent CSP bypasses
- Support for a large CSP policy
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.
π© Regarding the header Content-Security-Policy
, keep in mind that the policy applicability depends on the execution context. Technical details are available here. Therefore, CSP usage in a web API application implies to define the CSP in the document consuming the content of the 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'; base-uri '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 |
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:
- Spring Boot Actuator REST API:
Content-Type: application/vnd.spring-boot.actuator.v3+json
.
π‘ 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 Common Language Runtime (CLR) in use (see here for more details). |
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. |
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"
π 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.
-
π‘ If the web framework/web server you are using provides CORS features then always leverage them instead of implements it manually:
- List of web framework/web server supporting CORS.
- CORS middleware for Go by Julien Cretel.
-
π© 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.
π¬ 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
π¬ 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.
π¬ 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
- Otherwise return an HTTP 403 without any CORS related HTTP response headers.
π¬ 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
- Otherwise return an HTTP 403 without any CORS related HTTP response headers.
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 [...]
- https://portswigger.net/web-security/cors
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- https://jub0bs.com/posts/2023-02-08-fearless-cors/
- https://enable-cors.org/
- https://developer.mozilla.org/en-US/docs/Glossary/Origin
- https://cwe.mitre.org/data/definitions/942.html
- https://cwe.mitre.org/data/definitions/346.html
- OWASP WSTG - Testing Cross Origin Resource Sharing
- https://pkg.go.dev/github.com/jub0bs/cors
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.
π¬ 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.
π» 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.
- https://redbot.org
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
- https://caniuse.com/mdn-http_headers_cache-control
- https://cwe.mitre.org/data/definitions/525.html
- https://cwe.mitre.org/data/definitions/524.html
- OWASP WSTG - Testing for Browser Cache Weaknesses
- https://portswigger.net/kb/issues/00700100_cacheable-https-response
- https://portswigger.net/web-security/web-cache-poisoning
- https://portswigger.net/web-security/web-cache-deception
- https://portswigger.net/research/gotta-cache-em-all
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.
π 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.
π 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".
π It is the case for the base-uri directive.
πΊ This demonstration video show an example.
π‘ Therefore, ensure to always specify the base-uri
directive in a CSP policy to at least, the 'self'
value, to only allow the current domain to be specified as the document's base URI via a <base href="..." />
html tag.
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).