Application Security 101 – HTTP headers

Application Security 101 – HTTP headers

Tim

20th January 2022

17 min read

This article is the first in a series that will discuss some of the most common issues with HTTP headers, which are often relatively easy to implement and can have a significant impact on the overall security posture of your application. We’ve previously talked about the proactive and reactive styles of application development and security testing.

In this article, we discuss HTTP headers which are a common misconfiguration. With recent changes to some frequently used headers, we’re going to cover what each header is, does and how it offers you protection when using a web application.

Let’s take a look at each of the currently recommended security headers, their purpose and how to configure them as per security best practices. At the end of this blog, we’ll look at how popular web servers can be configured to include or modify HTTP response headers.

Before you read on:

  • Ideally, all the suggested security best practices found below should be tested, preferably in a test or development environment. If you can’t perform changes within separate environments, you should make backups of the current working configurations to ensure that you can revert to a working configuration should any changes break site functionality.
  • Not all browsers support every header. There is a handy tool that can be used to verify compatibility before HTTP headers are implemented. We recommend that you check this before implementing each of the headers discussed.

1. Strict-Transport-Security

The HTTP Strict Transport Security (HSTS) header forces browsers and other agents to interact with web servers over the encrypted HTTPS protocol, which secures users from Man in the Middle (MitM) attacks by protecting against protocol downgrade attacks. This header has been specified in RFC-6797.

You should ensure that your site is accessible over HTTPS before this header is implemented.

An example configuration of the HSTS header is shown below.

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

 

Parameter Description
max-age Defines the time in seconds that the browser or agent should be accessed only via encrypted HTTPS.
includeSubDomains HSTS security controls are applied to all subdomains.
preload Can be used to include the domain within Google Chrome’s HSTS preload list (Also used by other modern browsers).

 

2. X-Frame-Options

The X-Frame-Options HTTP header is used to define whether an application can be loaded in an iFrame within a third-party application. HTML iFrames are often used by malicious actors to create a fraudulent website, which mimics a legitimate application in an attempt to harvest user credentials. This is known as a “clickjacking” attack. This header is specified in RFC-7034

X-Frame-Options is easily implemented to deny a third-party application from loading your web application within iFrames. This can be achieved with the Content-Security-Policy (CSP) header, which we will discuss later. When this CSP directive has been implemented, the X-Frame-Options header becomes obsolete.

Deny ensures no rendering within a frame.

X-Frame-Options: deny

 

Parameter Description
deny Deny rendering within frames.
sameorigin Will deny rendering where there is an origin mismatch.
allow-from: Allow-from directive allows administrators to specify any domains that allow the site to be rendered from.

 

3. X-Content-Type-Options

The X-Content-Type-Options header was introduced to mitigate the threat of MIME sniffing attacks, preventing the browser from interpreting files as a different MIME type than what is specified in the Content-Type HTTP header. This can be used to inject client-side code into a user’s browser to steal sensitive information such as session cookies. You can read more about mitigating MIME attacks in this insightful article from Mozilla.

Parameter

Description
nosniff will prevent the browser from MIME-sniffing a response away from the declared content-type.

 

You can easily configure this header by setting the ‘nosniff’ directive, as demonstrated below.

X-Content-Type-Options: nosniff

 

4. Content-Security-Policy

The Content-Security-Policy (CSP) is a security standard that is used to mitigate XSS and clickjacking attacks and offers additional protections. It achieves this by allowing application developers to define where external resources (such as client-side JavaScript files) can be loaded from.

The CSP header is possibly the most difficult to configure correctly to achieve best security practice and maintain functionality. There are many directives that can be set, which without knowing their purpose, can lead to bypassing of intended protections if incorrectly configured.

There is a varying degree of support for each directive across browsers which adds to the complexity. Additional information on the CSP header and compatibility can be found on the Mozilla developer website. Configuring a secure but usable CSP can take some fine-tuning and will often take some experimenting to ensure security whilst maintaining the site’s desired functionality.

With that in mind, we will discuss the most commonly found misconfigured directive, the script-src directive. The script-src directive allows administrators to specify valid sources for JavaScript.

Take a look at the following examples.

Content-Security-Policy: script-src 'self'

 

This CSP on its own will only allow scripts to be loaded from the origin in which the document is served. This allows the browser to load JavaScript files from the same origin, where they have been included inside the web page. For example, where they have been specified in HTMLtag;

This is fine until you reach inline script tags; JavaScript that is loaded directly in the tag of an HTML document.

With the CSP header configured as above, this script won’t be executed as it’s in violation of the header configuration.

This is where the configuration of the CSP header can become complex, which can open a user to attack. Consider the next example.

Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval'

 

Here we’ve added two additional sources, ‘unsafe-inline’ ‘unsafe-eval’, which allows the use of inline resources, such as inline script elements, javascript: URLs, inline event handlers, inline style elements, the use of eval(), and similar methods for creating code from strings respectively.

Now, our alert script from before will execute the below, as this no longer violates the CSP.

These sources are often implemented to loosen the restrictiveness of the CSP where there may be a considerable number of web pages that rely on inline scripts, event handlers and style elements. However, this allows malicious actors to perform Cross-Site Scripting (XSS) attacks. (Please note that we will discuss the (now deprecated) X-XSS-Protection header further down).

Can inline scripts be used safely with the CSP header?

Yes, there are two ways that the CSP can be configured to allow inline scripts. The first is to use a base64 encoded nonce value, the second is to use a SHA hash. CSP supports the use of SHA256/384 and 512 hashes. Examples of how to set this up can be found here.

As already mentioned, this is just a small example of the most common misconfiguration we see within the CSP header. However, with time, the CSP should be configured appropriately so that it provides maximum security benefits as well as maintains site functionality.

What about X-Frame-Options?

As touched on in the X-Frames-Options section, the CSP can also be configured to block the loading of sites within iFrames. This can be achieved by setting the following ‘frame-ancestors’ parameter, where ‘domain.com’ refers to external domains that are permitted to load the site within frames. Additional domains can be added in the same manner.

Content-Security-Policy: "frame-ancestors 'self' 'domain.com'"

 

5. X-Permitted-Cross-Domain-Policies

This header is used to limit which data external resources, such as Adobe Flash and PDF documents, can access on the domain. Failure to set the X-Permitted- Cross-Domain-Policies header to “none” value allows other domains to embed the application’s data in their content.

If there is no requirement to load application data within web clients such as Adobe Flash Player or Adobe Acrobat (not limited to these), then the header should be configured as follows.

X-Permitted-Cross-Domain-Policies: none

 

Parameter Description
none Will prevent the browser from MIME-sniffing a response away from the declared content-type.
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 filenames are crossdomain.xml (i.e. URLs ending in /crossdomain.xml) are allowed.
all All policy files on this target domain are allowed.

 

6. Referrer-Policy

The Referrer-Policy header is used to determine what information is returned in the “Referrer” header. Failure to set an appropriate Referrer-Policy response header can lead to the disclosure of sensitive information to third-party web applications.

Parameter Description
no-referrer The Referrer header will be omitted entirely. No referrer information is sent along with requests.
no-referrer-when-downgrade This is the user agent’s default behaviour 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 in 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 of parameters) when performing a same-origin or cross-origin request.

The following example ensures that the Referred header is ignored and no information is passed within requests.

Referrer-Policy: no-referrer

 

7. Clear-Site-Data

The Clear-Site-Data header provides functionality for application developers to control which data is persistently stored within the browser’s various storage locations (cookies, storage APIs, cache). This can be useful for web developers, as they can instruct the browser to remove sensitive information stored on the client-side, such as cookies, caches, and storage, during a logout process. Note: This is only supported in secure contexts (HTTPS).

The following example sets the header to clear all types of data.

Clear-Site-Data: "*"

 

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

 

8. Cross-Origin-Embedder-Policy

The Cross-Origin-Embedder-Policy (COEP) header can be utilised to prevent a web browser from loading resources from third-party domains that don’t explicitly grant permission using Cross-Origin-Resource-Policy headers.

The following example header configuration can be used so that a document can only load resources from the same origin or those specifically identified as loadable from additional origins.

Cross-Origin-Embedder-Policy: require-corp

 

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

It should be noted that the Cross-Origin-Opener-Policy will need to be set as well. Additional information on the COEP header can be found here.

 

9. Cross-Origin-Opener-Policy

The Cross-Origin-Opener-Policy (COOP) header is used to segregate cross-origin browsing contexts within a web browser. A browsing context is an environment in which a browser displays a document object to the user, for example, a tab, window or iframe. This header is used to prevent a specific set of cross-origin attacks known as XS-Leaks.

The following example header configuration can be used to isolate the browsing context exclusively to same-origin documents. Cross-origin documents are not loaded in the same browsing context.

Cross-Origin-Opener-Policy: same-origin

 

Parameter 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 that either doesn’t set COOP or opt-outs 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.

Additional information on the implementation of COEP and COOP headers can be found here.

 

10. Cross-Origin-Resource-Policy

The Cross-Origin-Resource-Policy (CORP) header is used by developers to define whether a user’s browser is able to make requests to an application or web service from a different origin. The header is used to prevent side-channel and Cross-Site Script Inclusion attacks.

The following example header configuration can be used so that only requests from the same origin can read the resource.

Cross-Origin-Resource-Policy: same-origin

 

Parameter 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 a CORP header is not specified.

 

11. Cache-Control

The Cache-Control header is used to instruct browsers and shared caches on how they should cache information. Sensitive information may be cached to local storage where it can be viewed by unauthorised malicious actors on devices such as shared computers in internet cafes.

This header is often misconfigured by still allowing caching even when set or is missing entirely, which can be a problem when users start to access sensitive data on shared devices as described above.

The following example configuration instructs the browser that no caching is allowed, any previously cached resources are cleared and provide support for HTTP/1.0 caches.

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

 

Parameter 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 in 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 in any cache, even if the response is normally non-cacheable.
private The response may be stored only in 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= The maximum amount of time a resource is considered fresh. Unlike Expires, this directive is relative to the time of the request.
s-maxage= Overrides max-age or the Expires header, but only for shared caches (e.g. proxies). Ignored by private caches.

For more information on HTTP caching, check the Mozilla Developer website here.

 

12. X-XSS-Protection

This header is now deprecated. We see many applications where this is still configured incorrectly. However, there’s a catch. The Content-Security-Policy can be utilised to protect users from XSS attacks, as long as it’s configured appropriately. It’s recommended that if support for legacy browsers isn’t required, this header should be disabled (shown below) and the CSP header used instead.

X-XSS-Protection: 0

 

Where this isn’t possible, the X-XSS-Protection header should be enabled.

Web Server Configuration

In the following section, we will look at how to implement the headers described above in several popular web servers, such as Apache, nginx and IIS. However, the configuration of most web servers will be similar and can likely be implemented in a similar way. You should check vendor-specific documentation for more information.

Some software packages, such as WordPress, provide plugins that can be used to easily configure HTTP response headers. However, such plugins can often introduce their own security risks and care should always be taken when downloading and installing third-party plugins.

Apache Server

The Apache extension ‘headers_module’ must be enabled in the Apache configuration to enable the configuration and modification of HTTP response headers within the Apache webserver.

It’s possible to load the module with the following command.

sudo a2enmod headers
// Restart the service
sudo service apache2 restart

 

Once enabled, you can now add configuration lines to your Apache2 config file. The location of this file may vary depending on the environment and your specific setup. For this demonstration, we will use the 000-default.conf file. However, you should use your own configuration file.

Our configuration file looks like the below.

ServerName localhost
DocumentRoot /var/www/html
DirectoryIndex test.html

 

From here, we can now continue to configure the HTTP response headers. For example, should we want to add the X-Frame-Options header to test that the site cannot be loaded into an iframe, we can add this in the format ‘Header Set HEADER-NAME VALUE’.

ServerName localhost
DocumentRoot /var/www/html
DirectoryIndex test.html
Header Set X-Frame-Options deny

 

Now, when we access our site, we can see that the X-Frame-Options header is set, and we are blocked from loading this site within an iframe. We can continue in the same manner to add headers and test the application.

ServerName localhost
DocumentRoot /var/www/html
DirectoryIndex test.html
Header Set X-Frame-Options deny
Header Set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header Set X-Content-Type-Options "nosniff"
Header Set Content-Security-Policy "default-src 'self';"
Header Set Referrer-Policy "no-referrer"
Header Set X-Permitted-Cross-Domain-Policies "none"
Header Set Cross-Origin-Embedder-Policy "require-corp"
Header Set Cross-Origin-Opener-Policy "same-origin"
Header Set Cross-Origin-Resource-Policy "same-origin"
Header Set Cache-Control "no-store, max-age=0"
Header Set Pragma "no-cache"
Header Set X-XSS-Protection "0"

 

Please note

All changes to the configuration file require the Apache2 service to be restarted before the changes take effect. When we access our test site with a browser and check the Network tab inside the developer tools, we can see that the response headers set above are now returned by the webserver.

 

Nginx Server

Like the Apache server configuration, nginx requires modification of local config files (nginx.conf) to implement HTTP response headers. For nginx, we can add these in the format ‘add_header HEADER-NAME VALUE’.

After adding the above headers, our configuration file looks like the following:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;events {
worker_connections 768;
# multi_accept on;
}http {##
# Basic Settings
####
# Headers
##
Header Set X-Frame-Options deny
Header Set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header Set X-Content-Type-Options "nosniff"
Header Set Content-Security-Policy "default-src 'self';"
Header Set Referrer-Policy "no-referrer"
Header Set X-Permitted-Cross-Domain-Policies "none"
Header Set Cross-Origin-Embedder-Policy "require-corp"
Header Set Cross-Origin-Opener-Policy "same-origin"
Header Set Cross-Origin-Resource-Policy "same-origin"
Header Set Cache-Control "no-store, max-age=0"
Header Set Pragma "no-cache"
Header Set X-XSS-Protection "0"

 

Again, after stopping the Apache web server and starting the nginx web server, we can see that the headers are still applied when accessing the test site.

Internet Information Services (IIS)

IIS can be configured with the IIS Manager. Within the Site, configure the ‘HTTP Response Headers’ setting for the required site. In this demo, we’re using the “Default Web Site”.

 

Once in the HTTP Response Headers setting, configure response headers by right-clicking and choosing “Add…”. Add each header and test as required, once complete you may have something similar to the below.

Restart the IIS service and access your site, you should now see the new HTTP response headers returned in HTTP responses.

HTTP headers are a relatively easy way to improve your application security. Keeping up to date with the most current headers will help you implement security best practices and protect your web application. Stay tuned as we’ll be revisiting HTTP security headers in this blog series to ensure you’re equipped with the knowledge you need to stay secure. If you feel like you need some more assistance, check out our website penetration testing services or contact us today.

Resources

  • Insights
  • Labs
API penetration testing

Securing APIs through penetration testing

APIs (Application Programming Interfaces) have become the backbone of many modern applications, and indeed the foundation of some businesses services. APIs enable seamless communication between…

The importance of a post-penetration test action plan

The importance of a post-penetration test action plan

As cyber threats continue to evolve and become more sophisticated, businesses must stay one step ahead in protecting their sensitive data and network infrastructure. Penetration…

How to choose the right penetration testing partner

How to choose the right penetration testing partner for your business

In today’s digital landscape, cybersecurity threats are evolving at an alarming rate. With the growing number of cyber-attacks and data breaches, businesses must prioritise their…

IoT device security, penetration testing

Securing the Internet of Things: Penetration testing’s role in IoT device security

The world is witnessing a remarkable transformation as more devices become interconnected, forming what’s known as the Internet of Things (IoT). From smart refrigerators and…

Man working as a junior penetration tester

My first month working as a junior penetration tester

Entering the world of cyber security as a junior penetration tester has been an eye-opening experience for me. In my first month, I’ve encountered challenges,…

The role of penetration testing in cybersecurity

The role of penetration testing in cybersecurity

Cybersecurity forms the backbone of safeguarding your business’s data. With cybercrime becoming more sophisticated, traditional security measures are often insufficient. Staying vigilant and proactive is…

Password cracking: How to crack a password

An introduction to password security: How to crack a password

Online Password Cracking An online attack is performed in real-time, against live services or applications to compromise active user accounts. Such attacks typically occur when…

Application Security 101 – HTTP headers

Application Security 101 – HTTP Headers Information Disclosure

Server Header Information Disclosure The most common HTTP header that is enabled by default in most web servers is the ‘Server’ header, which can lead…

SPF, DKIM, DMARC and BIMI for Email Security

SPF, DKIM, DMARC and BIMI for Email Security

Sender Policy Framework Sender Policy Framework (SPF) is a DNS TXT record that is added to a domain that tells email recipients which IP addresses…

Terraform security best practices

Terraform security best practices (2022)

The following sections discuss our most important Terraform security best practices: The importance of Terraform State Terraform must keep track of the resources created. When…

Security vulnerability in Follina exploit

Preventing exploitation of the Follina vulnerability in MSDT

The Follina Exploit A zero-click Remote Code Execution (RCE) vulnerability has started making the rounds which is leveraging functionality within applications such as Microsoft Word.…