HTTP security headers: An easy way to harden your web applications
Modern browsers support a wide array of HTTP headers that can improve web application security to protect against clickjacking, cross-site scripting, and other common attacks. This post provides an overview of best-practice HTTP security headers that you should be setting in your websites and applications.
Your Information will be kept private.
Your Information will be kept private.
What are HTTP security headers?
HTTP security headers are a subset of HTTP headers that is related specifically to security. They are exchanged between a client (usually a web browser) and a server to specify the security details of HTTP communication. There are also other HTTP headers that, although not directly related to privacy and security, can also be considered HTTP security headers.
Setting suitable headers in your web applications and web server settings is an easy way to greatly improve the resilience of your web application against many common attacks, including cross-site scripting (XSS) and clickjacking attacks. This post only lists the most important headers – see our white paper on HTTP security headers for a more detailed discussion of available security headers.
How HTTP security headers can improve web application security
When we talk about web application security on this blog, we often mean finding exploitable vulnerabilities and fixing them in application code. HTTP security headers operate on a different level, providing an extra layer of security by restricting behaviors permitted by the browser and server once the web application is running. Implementing the right headers in the right way is a crucial aspect of any best-practice application setup – but how do you choose the ones that make the biggest difference?
As with other web technologies, HTTP protocol headers come and go depending on current protocol specifications and support from browser vendors. Especially in security, where de facto standards can arise and fall out of favor quite independently of official specs, it’s not unusual to find headers that were widely supported a few years ago but are deprecated today. At the same time, completely new proposals can gain universal support in a matter of months. Keeping up with the latest developments is not easy, but leading application security solutions such as Invicti can help by automatically checking for the presence and correctness of HTTP security headers and providing clear recommendations.
The most important HTTP security headers
First up are the three best-known and probably most important HTTP response headers that any modern web application should be setting to immediately rule out entire classes of web attacks.
When enabled on the server, the HTTP Strict Transport Security header (HSTS) enforces the use of encrypted HTTPS connections instead of plain-text HTTP communication. A typical HSTS header might look like this:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
This informs any visiting web browser that the site and all its subdomains use only SSL/TLS communication, and that the browser should default to accessing it over HTTPS for the next two years (the
max-age value in seconds). The
preload directive indicates that the site is present on a global list of HTTPS-only sites. The purpose of preloading is to speed up page loads and eliminate the risk of man-in-the-middle (MITM) attacks when a site is visited for the first time.
Invicti checks if HSTS is enabled and correctly configured.
The Content Security Policy header (CSP) is something of a Swiss Army knife among HTTP security headers. It lets you precisely control permitted content sources and many other content parameters and is recommended way to protect your websites and applications against XSS attacks. A basic CSP header to allow only assets from the local origin is:
Content-Security-Policy: default-src 'self'
Other directives include
img-src to specify permitted sources for scripts, CSS stylesheets, and images. For example, if you specify
script-src 'self', you are restricting scripts (but not other content) to the local origin. Among other things, you can also restrict browser plugin sources using
plugin-types (unsupported in Firefox) or
Invicti checks if the CSP header is present.
This header was introduced way back in 2008 in Microsoft Internet Explorer to provide protection against cross-site scripting attacks involving HTML iframes. To completely prevent the current page from being loaded into iframes, you can specify:
Other supported values are
sameorigin to only allow loading into iframes with the same origin and
allow-from to indicate specific permitted URLs. Note that nowadays, this header can usually be replaced by suitable CSP directives.
Invicti checks if the X-Frame-Options header is present.
Examples of deprecated HTTP security headers
As already mentioned, some headers get introduced as temporary fixes for specific security issues. As web technology moves on or standards catch up, these become deprecated, often after only a few years. Here are two examples of deprecated headers that were intended to address specific vulnerabilities.
As the name suggests, the
X-XSS-Protection: 1; mode=block
Created for browsers equipped with XSS filters, this non-standard header was intended as a way to control the filtering functionality. In practice, it was relatively easy to bypass or abuse. Since modern browsers no longer use XSS filtering, this header is now deprecated.
Invicti checks if you have set X-XSS-Protection for your websites.
HTTP Public Key Pinning (HPKP) was introduced in Google Chrome and Firefox to solve the problem of certificate spoofing. HPKP was a complicated mechanism that involved the server presenting clients with cryptographic hashes of valid certificate public keys for future communication. A typical header would be something like:
Public-Key-Pins: pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; max-age=5184000
In practice, public key pinning proved too complicated to use. If configured incorrectly, the header could completely disable website access for the time specified in the
max‑age parameter (in the example above, this would be two months). The header was deprecated in favor of certificate transparency logs – see the
Expect-CT header below.
Other useful HTTP security headers
While not as critical to implement as CSP and HSTS, the additional headers below can also help you harden your web applications with relatively little effort.
The recommended way to prevent website certificate spoofing is to use the
Expect-CT header to indicate that only new certificates added to Certificate Transparency logs should be accepted. A typical header would be:
Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"
enforce directive instructs clients to refuse connections that violate the Certificate Transparency policy. The optional
report-uri directive indicates a location for reporting connection failures.
Invicti reports missing Expect-CT headers with a Best Practice severity level.
When included in server responses, this header forces web browsers to strictly follow the MIME types specified in
Content-Type headers. This is specifically intended to protect websites from cross-site scripting attacks that abuse MIME sniffing to supply malicious code masquerading as a non-executable MIME type. The header has just one directive:
Invicti checks if Content-Type headers are set and X-Content-Type-Options: nosniff is present.
Fetch metadata headers
This relatively new set of client-side headers allows the browser to inform the server about application-specific HTTP request attributes. Four headers currently exist:
Sec-Fetch-Site: Specifies the intended relationship between the initiator and target origin
Sec-Fetch-Mode: Specifies the intended request mode
Sec-Fetch-User: Specifies if the request was triggered by the user
Sec-Fetch-Dest: Specifies the intended request destination
When supported by both the server and the browser, these headers provide the server with additional information about intended application behaviors to help identify and block suspicious requests.
Related HTTP headers to improve privacy and security
These final items are not strictly HTTP security headers but can serve to improve both security and privacy.
This controls how much (if any) referrer information the browser should reveal to the web server. Typical usage would be:
With this header value, the browser will only reveal its full referrer information (including the URL) for same-origin requests. For all other requests, only information about the origin is sent.
Invicti reports missing Referrer-Policy headers with a Best Practice severity level.
This header allows you to control the caching of specific web pages. Several directives are available, but the typical usage is simply:
This prevents any caching of the server response, which can be useful for ensuring that confidential data is not retained in any caches. You can use other available directives to get more precise control over caching behavior.
If you want to ensure that confidential information from your application is not stored by the browser after a user logs out, you can set the
This directive will clear all browsing data related to the site. The
storage directives are also available to give you more fine-grained control over what is cleared.
This is an experimental header that allows you to deny access to specific browser features and APIs on the current page. It can be used to control application functionality but also to improve privacy and security. For example, if you want to deny an application permission to access the microphone and camera APIs, you can send the following header:
Feature-Policy: microphone 'none'; camera 'none'
Many more directives are available – see the Feature-Policy documentation on MDN for a full list.
Security headers in action with Sven Morgenroth
Invicti security researcher Sven Morgenroth joined Paul Asadoorian on Paul’s Security Weekly #652 to describe and demonstrate various HTTP headers related to security. Watch the full video interview and demo:
Keep track of your HTTP security headers with Invicti
HTTP security headers can be an easy way to improve web security and often don’t require changes to the application itself, so it’s always a good idea to use the most current headers. However, because browser vendor support for HTTP headers can change so quickly, it’s hard to keep everything up-to-date, especially if you’re working with hundreds of websites.
To help you keep up and stay secure, Invicti provides vulnerability checks that include testing for recommended HTTP security headers. Invicti checks if a header is present and correctly configured, and provides clear recommendations to ensure that your web applications always have the best protection.