code

HTTP Security Headers

Written by Itamar Rom on

HTTP Security Headers

Written by Itamar Rom on


Introduction

As web applications continue to utilize new and advanced technologies, these technologies can sometimes introduce risks and unknowingly expose them to different vulnerabilities.

To achieve the goal of making applications as secure as possible, HTTP security headers are a small implementation that can make a huge difference. 

What are HTTP Headers?

In this article, we will examine the recommended security headers according to OWASP and how they help prevent security vulnerabilities such as Cross-site scripting (XSS), Clickjacking, Information disclosure, and more. We will also review some now-deprecated headers as they are no longer relevant and may even pose a security risk to an otherwise secure application.

We will also discuss the importance of manual and automated testing, as well as how to review web application security.

Why HTTP Headers Matter

Security headers in HTTP aim to protect users by enforcing strict rules and limitations during data exchanges between clients and servers. These headers add an extra layer of protection by restricting insecure browser behaviors and helping prevent common, avoidable vulnerabilities. While it’s important to balance usability and security, many of these headers are considered industry best practices and can significantly improve any web application’s security.

A Closer Look at Each Header

X-Frame-Options

Web developers use these headers to control browser behavior when interacting with their sites. It declares a policy stating whether the browser may display the page’s contents when embedded using a frame in another website. It blocks any site from presenting the protected page’s contents inside of a “framing” element such as <frame>, <iframe>, <object>, and <embed>.

The X-Frame-Options header includes the following directives:

DENY 

The DENY  value will disallow displaying the contents in a frame completely. 

SAMEORIGIN (optional) 

Allows framing the contents only by pages of the exact origin. If you wish to use this setting, consider that it may still introduce security issues as it doesn’t protect against attacks using multiple nested frames.

ALLOW-FROM (deprecated)

Permits embedding only by a specified domain. Do not use this option, as it is already deprecated. Modern browsers will completely ignore this header when used.

According to OWASP, the recommended value of this header is as follows:

X-Frame-Options: DENY

If possible, using the Content Security Policy (CSP) frame-ancestors directive is most recommended as it obsoletes the X-Frame-Options header, but in cases using CSP directives isn’t an option, X-Frame-Options: DENY  provides excellent protection against clickjacking attacks for most web applications.

Strict Transport Security

When a web server sends the HTTP Strict Transport Security (HSTS) header, it tells browsers to interact with the web application only over HTTPS. This restriction blocks access via insecure HTTP connections and helps prevent Man-in-the-Middle (MitM) and cookie hijacking attacks.
The HSTS header includes the following directives:

Max-age  =  {seconds}

This required directive tells the client how long (in seconds) to access the server using HTTPS by default. The recommended value is 2 years. Setting this value to 0 will cancel this behavior.

includeSubDomains

Specifying this optional, although recommended directive, will also enforce the policy on the host’s subdomains. This option is more secure, but understandably, it will block any attempt to serve a page’s content over HTTP.

preload

The preload directive helps enhance the header’s security but also has some repercussions that should be considered before implementation.

If users access your web application for the first time over HTTP, the browser will ignore the HSTS header. By specifying the preload directive, you can add your domain to the HSTS preload list, which Chrome maintains and other browsers also use. This tells browsers to always access your domain using HTTPS. If you’re unsure about serving your content over HTTPS long-term, keep in mind that removing your domain from the preload list can take a long time. It’s a good idea to review the preload removal process before deciding to use this directive.

Recommended Settings

The recommended settings for this header provided by OWASP are as follows:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
The preload directive is optional, but it affects security. Omitting it may work in most cases, yet including it in the header provides the strongest protection.

It is also important to note that any misconfiguration of the header or technical issues with the SSL/TLS certificate can make the web application inaccessible to legitimate users. For example, suppose the certificate expires or is revoked before the header’s duration is over. In that case, users might be unable to access the application until the header duration expires.

X-Content-Type-Options

By setting the X-Content-Type-Options with the nosniff directive, which is the only directive available, the server blocks the browser from performing MIME sniffing and instructs it to strictly adhere to the content type declared by the server.
MIME sniffing is an action browsers perform to guess the content type of served media when it cannot be explicitly determined from the response. Each browser performs content sniffing differently. For example, Firefox will either look at contextual clues like the HTML element that triggered the fetch or inspect the magic bytes of the retrieved media.

This behavior can introduce security risks by opening an attack vector called MIME Confusion, which occurs when an attacker manipulates the content of a file to trick the browser into misinterpreting its MIME type. This attack vector includes potential exploits such as content spoofing, Cross-Site Scripting (XSS), and unintended execution of malicious client-side code. 

Recommended Setting

OWASP recommends including the X-Content-Type-Options header with the nosniff  directive as part of the HTTP security response headers
X-Content-Type-Options: nosniff

Content- Security- Policy

This header, already a web security standard, could fill an entire article. Here, we’ll cover it briefly. For a deeper understanding of its features, directives, and customization, consult the OWASP Content Security Policy Cheat Sheet in the references.

Content Security Policy (CSP) helps secure web applications by specifying the allowed sources for content like scripts, stylesheets, images, and fonts. Developers implement CSP by defining a set of directives that tell the browser what content it can load and how to handle policy violations. For instance, a CSP directive might allow scripts to run only from approved domains or block inline script execution entirely. This can help prevent attackers from injecting malicious scripts into a website, as the browser will refuse to execute scripts that violate the policy.

CSP generally helps mitigate the risks of attacks such as Cross-Site Scripting (XSS), Clickjacking, and other client-side code injection attacks. It is more applicable to pages that render and execute scripts or code and less so for REST API responses, where the content returned is not being rendered.

Note that implementing a proper CSP requires careful tuning because, if enabled, CSP has a significant impact on the way browsers render pages.

Example Policy

There is no recommended setting, as the CSP use cases change with each application.

The following is a common restrictive example that covers potentially unsafe entities.

Content-Security-Policy: default-src ‘self’; frame-ancestors ‘self’;

script-src ‘self’; object-src ‘none’;

Referrer-Policy

The Referrer-Policy header controls how much referrer information should be included with requests (sent via the Referrer header).

Currently, the default behavior of browsers is to send full referrer information when viewing a page on the same origin (which includes the URL origin, path, and query string), but when sending cross-origin requests, the referrer header only includes the origin part of the URL.

This behavior usually provides enough protection. However, because some users may use outdated browsers or require a stricter or more permissive Referrer Policy, the web application can include the Referrer Policy in its response headers.

The Referrer-Policy header includes the following directives:

no-referrer

The sent requests will not include any referrer information.

no-referrer-when-downgrade

The browser sends the full URL as long as the connection maintains the same or a higher security level. It limits referrer information only when the connection downgrades or switches to a different protocol (this behavior may vary between browsers).

origin

It will only include the origin with sent requests.

origin-when-cross-origin

When cross-origin requests are made, only the origin will be included. this includes 

connection downgrading.

same-origin

A full URL will be sent when requests are on same-origin requests but when cross-origin 

doesn’t include any referrer information.

strict-origin

It will send the origin when the HTTP protocol security is not changed, and if 

downgraded, don’t include any referrer information.

Strict-origin-when-cross-origin (default)

This is the default browser behavior. It will send the full URL on same-origin requests 

and include only the origin on cross-origin requests. Also, if the connection is 

downgraded, referrer information will not be included.

Unsafe-url (unsafe)

It will include the entire URL on any request. Do not use this setting, as it can potentially

disclose sensitive information. 

Recommended Setting

The recommended setting for this header provided by OWASP is as follows:

Referrer-Policy: strict-origin-when-cross-origin

Clear-Site-Data

This header clears browsing data associated with the requesting website (cookies, storage, cache, etc). This header lets developers control the data a client browser stores for their origins, based on the response URL. It helps with actions like logging out a user, but it shouldn’t be relied on alone, as browser support for its directives varies.

The Clear-Site-Data header includes the following directives:

“cache”

The browser will remove locally cached data (the browser cache). Depending on the browser used,  Additional cached data may also be removed.

“clientHits”

Indicates that the server wishes to remove all client hints (will be removed with “cache”, “cookies”, or “*” as well).

“cookies”

Using this directive will remove all cookies for the origin of the response URL from the browser and HTTP authentication credentials. This also includes all subdomains of the origin.

“storage”

Indicates that the server instructs the browser to remove all DOM storage for the origin.

“executionContexts”

Indicates that the server instructs the browser to reload all browsing contexts for the origin (like refreshing the current URL), currently only supported by a small subset of browsers

“*”

Will clear all types of data from the browser for the origin. Any future data types will also be covered as well.

Example Policy

The following example clears the browser’s cache, cookies, and storage for the origin:
Clear-Site-Data: “cache”, “cookies”, “storage”

Cache-Control

The Cache-Control header uses different directives to specify a resource’s caching behavior. It controls how browsers (client-side) and intermediary caches like proxy servers (server-side) store and use that resource.

It helps mitigate several cache-related attacks, such as Replay attacks, Session hijacking, Injection attacks, and Cache poisoning.

The Cache-Control header includes the following directives:

public

This directive lets any cache—client-side or server-side—store the response. Caches can then serve the stored content to any user who makes a subsequent request. When marking content as public, developers must carefully consider the risk of exposing sensitive information unintentionally.

private

Including the private directive tells the browser to cache the response only for a single user—typically on the client side. Shared caches, such as proxies or CDN edge servers, will not store this response. Only the user’s browser or another private cache linked to that user can store it.

no-cache

Using no-cache doesn’t prevent caching. Instead, it tells caches to store the response but revalidate it with the origin server before serving it. Both client-side and server-side caches can keep the content, but they must confirm its validity before delivering it. Revalidation happens only when the cached content becomes stale or expires.

no-store

The no-store directive means caches cannot store the response. This applies to all caches and is typically used for sensitive or dynamically generated content.

max-age

This directive sets the maximum time (in seconds) a response can be cached. Once that time passes, the cached response becomes stale.

s-maxage

This directive is similar to the max-age directive but is explicitly applied for shared caches. It will override any max-age or Expires header if present. 

must-revalidate

The must-revalidate directive is similar to the no-cache directive. The difference is that the system revalidates the content on every request, regardless of its freshness.

proxy-revalidate

Similar to the must-revalidate directive, but applied specifically for shared caches. 

no-transform

The no-transform directive instructs shared caches not to modify the response’s content in any way. This includes preventing transformations like compression or encryption. 

It is particularly useful for resources like JavaScript files or images where it is important to ensure the integrity and structure of the data. 

Example Policy

The following example sets the caching behavior of that content to only use private caches, revalidate the content with the server when expired, and is immediately stale when served:
Cache-Control: private, no-cache, max-age=0

Cross-Origin-Embedder-Policy (COEP)

This header configures the embedding of cross-origin resources into the document. This header controls whether a resource can be embedded via iframes or objects. It reduces the risk of cross-origin attacks and data leaks by blocking unsafe cross-origin content.

The COEP header includes the following directives:

unsafe-none (default)

This directive allows embedding content without restrictions. It does not require adhering to a CORS policy or the CORP header.

require-corp

This directive states that the document can only embed content from the same origin or cross-origin content explicitly marked as loadable. It also ensures that cross-origin embedded content can only load content from the same origin (content’s origin).  If not, it will be blocked by the COEP header. So be aware that any cross-origin resources not configured correctly will be blocked when this directive is set.

Recommended Setting

The recommended setting for this header provided by OWASP is as follows:

Cross-Origin-Embedder-Policy: require-corp

Cross-Origin-Opener-Policy (COOP)

The COOP header establishes boundaries between documents from different origins. It ensures that a top-level document does not share a browsing context group with any opened cross-origin content, for example, via iframe or popups.
Its main goal is to mitigate security risks associated with cross-origin interactions, which can cross the security boundary established by the Same Origin Policy (SOP), therefore protecting the integrity of the documents. This is applied to both the opener and the opened documents.

The COOP header includes the following directives:

unsafe-none (default)

This directive allows both the opened and its opener documents to be in the same browsing context group without cross-origin restrictions. If either of them has a COOP of same-origin or same-origin-allow-popups, they will be isolated.

same-origin-allow-popups

This directive will isolate the browsing context of the documents unless they are of the same origin. With this directive set, the opener document can open cross-origin content in a new window.

same-origin

The same-origin directive is the most restrictive. It will block any interaction with opened content unless it is of the same origin. The browsing context of both documents will be completely separate.

Recommended Setting

The recommended setting for this header provided by OWASP is as follows:

Cross-Origin-Opener-Policy: same-origin

Cross-Origin-Resource-Policy (CORP)

The CORP header controls whether resources like CSS, images, and scripts can be fetched by the origin. It strengthens the Same Origin Policy by applying the same restrictions to these resources, even when they come from different origins.

This header’s primary goal is to mitigate security risks associated with loading resources from untrusted or potentially malicious origins.

CORP directives:

same-origin

Specifies that only requests from the same origin can fetch the resource using the Same Origin Policy.

same-site

This directive allows fetching resources only if they are from the same site.

Cross-origin (default)

If CORP is not specified, this is the default policy that the browser will follow. It permits unrestricted cross-origin resource fetching.

Recommended Setting

The recommended setting for this header provided by OWASP is as follows:
Cross-Origin-Resource-Policy: same-site

Testing Security Header Configurations

Reviewing your security header configurations is important in understanding the web application’s current security posture. There are several ways this can be done. One such way is performing an automated assessment using an open-source tool such as the Mozilla Observatory.
Mozilla Observatory is a user-friendly tool that can help assess the effectiveness of your security headers. The Observatory scans your web application and evaluates security-related practices, including implemented secure headers like CSP, HSTS, and more. To use the Mozilla Observatory, simply input your web application’s URL, and the tool will generate a detailed report highlighting strengths and areas for improvement.

Running the Observatory Security Assessment on an Example Domain

It is important to note that the test results are added to a public list saved online. To use this tool confidentially, download the Observatory Scanner and use a local installation to run your tests.

The Importance of Manual Testing

While automated tools like the Mozilla Observatory offer a convenient way to quickly overview your web application security configurations, it is important to acknowledge their limitations. These tools provide valuable insight but may not catch all the intricacies and nuances specific to your application. Therefore, conducting a more thorough and accurate manual assessment is important to ensure your web application security configurations are as effective as possible.

Conclusion

Implementing robust HTTP security headers is crucial in fortifying web applications against several potential vulnerabilities. Organizations must maintain a thorough, up-to-date understanding of current and deprecated security headers to protect their applications and users from potential threats.

Organizations should prioritize cyber security risk assessments and penetration tests to mitigate risks in web application deployments, which have become increasingly popular among companies developing SaaS products. Clear Gate, a trusted cybersecurity provider, offers in-depth manual penetration tests to help organizations strengthen their security,  including security headers implementations discussed in this article, and, as a result, protect valuable data from potential threats.

References