Security in HTTP Headers

There are many cyber security related topics that I could have chosen to write about, and HTTP headers seems to be a less interesting one. The reason I chose this topic is because the reports I deliver to clients always have the same issue, and that is either missing or misconfigured HTTP headers.

In this blogpost, I will discuss the details of different HTTP headers that are easy to implement and will help to improve the overall security of a website.

Introduction to HTTP Headers

HTTP headers are included in communications between clients and servers. Clients in this case would be the user, using a web browser to surf a website, hosted on a server. In a nutshell, requests are sent to the server when you perform actions whilst surfing a website. The server will reply with responses and web browsers will neatly display them for you.

The below screenshot shows an example of HTTP headers in both a request and response whilst navigating to our home page. I used Firefox and its built-in developer tools. If you want to try this yourselves, right click anywhere on a webpage, click “Inspect Element” and navigate to the “Network” tab. You may need to refresh the webpage if you only had the developer tools opened after navigating to your target website.

Over the years, technologies like AWS, CloudFlare and Web Application Firewalls (WAF) implemented custom HTTP headers. They may be used for specific functionalities, and others may just be there for branding purposes and helps us identify what kind of technology your website is using. The below lists the top five HTTP security headers that I have often seen missing from websites.

  • Strict-Transport-Security (HSTS)
  • X-Frame-Options
  • X-Content-Type-Options
  • X-XSS-Protection
  • Content-Security-Policy

Please note that these are server-side headers. When implemented, web servers will include these in HTTP responses to instruct browsers to apply the security restrictions.

Strict Transport Security (HSTS)

The HSTS header instructs browsers to always communicate with the server using HTTPS. This increases security by encrypting both client-side and server-side communications, stopping attackers performing man in the middle attacks from reading sensitive information whilst they are transmitted over the network. Although difficult to exploit in a real-world scenario, as attackers will have to position themselves between a website user and the server, this could still pose a significant risk in the case of a targeted campaign.

Implementing the HSTS security header for websites are fairly straightforward; however, it could vary depending on the technology your application is built on as well as the hosting provider you are using. You will need to refer to your vendor’s documentations; however, we will be happy to help if required, feel free to contact us. Ultimately, a HSTS security header looks like the one below, with the “max-age” value set to a desired period in seconds, in this case 180 days. This will instruct clients to always communicate with the server via HTTPS for the next 6 months.

strict-transport-security: max-age=15552000; includeSubDomains; preload

The HSTS header should always be sent over a security transport layer. This is because when a browser visits a website for the first time, they will have no knowledge of the existence of HSTS policies defined by the server. When visiting a website for the very first time, malicious attackers who are already performing a man in the middle attack could intercept and strip out the HSTS header in the server responses. This will then allow an attacker to continue intercepting and read all your communications with the server in clear text.

For this very reason, browsers maintain a HSTS preload service with a list of websites that will be loaded using HTTPS, even when a browser visits a website for the very first time. To implement this, simply include the “preload” directive in the HSTS header as shown in the example above. The “includeSubDomains” directive does what it says on the tin, which means that the HSTS policy will also be defined for every subdomain under your website.

X-Frame-Options

The “X-Frame-Options” header instructs browsers not to load a webpage when it is embedded in “iframe” tags. An attacker leveraging on this flaw could launch social engineering campaigns to target victims with clickjacking attempts. When a webpage can be included in “iframe” tags, an attacker can socially engineer a scenario to get victims to visit a website under their control. In other words, the victim would visit a malicious website that looks like the victim website, and all the actions performed would be sent to the attacker’s server instead. This includes login credentials if the website’s login page is vulnerable to clickjacking.

There are two possible configurations you can implement the “X-Frame-Options” header with, and they look like this:

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

The “DENY” directive instructs browsers to never allow inclusion of the webpage in any kind of frames. The “SAMEORIGIN” directive is a more relaxed alternative, allowing the webpage to be included in frames belonging to the same origin website.

X-Content-Type-Options

The “X-Content-Type-Options” header helps mitigate content sniffing attacks. When a browser receives a server response, they perform an educated guess on the type of contents within the response. In certain circumstances, an attacker leveraging on content sniffing attacks by injecting malicious code in server responses could potentially trick a browser to perform unwanted actions, such as executing JavaScript code to perform cross-site scripting attacks.

By specifying an “X-Content-Type-Options” header, browsers will no longer perform educated guesses. Server responses will be evaluated according to the value defined in the “Content-Type” header instead, preventing attackers from performing content sniffing attacks. Implementing this security header can be done as follows:

X-Content-Type-Options: nosniff

X-XSS-Protection

The “X-XSS-Protection” header provides additional protection against cross-site scripting (XSS) attacks. Certain web browsers have built-in XSS filters that would prevent the execution of JavaScript payloads. When a browser receives a response from a web server and detects that JavaScript code will be executed, the XSS filters will trigger and replaces the potentially malicious code with something inexecutable. I believe that different browsers will behave differently in their XSS filters and I have tangled with IE and Edge in the past. For example, consider the following code, which is a classic XSS payload:

<img src=x>

In my past experience, IE and Edge XSS filters will replace the character “o” in “onerror” with a hashtag, resulting in the following being displayed on the browser:

<img src=x #nerror=alert(document.cookie)>

This would prevent the XSS payload from firing, hence providing additional security; however, I have proven to our clients many times that XSS filters are unreliable. By investing additional time in playing around with my XSS payloads, I have found that these filters can be bypassed. The following payload was used in a recent test, where a null byte character was used:

<img src=x%00onerror=alert(document.cookie)>

As I am not involved in the development of these filters, it is difficult for me to say how they work. My best guess is that they are implementing this via a blacklist approach, reading specific event handlers such as “onerror” and “onload” and replacing the leading “o” characters with hashtags. As such, by including a null byte character, “%00” bypasses the filters.

At the time of writing, mainstream browsers such as Chrome and Edge appear to be deprecating support for the “X-XSS-Protection” header in their browsers, with Firefox completely disregarding the idea of supporting it. The “Content-Security-Policy” (CSP) header will be preferred in place of the “X-XSS-Protection” header, as it is widely supported and better implemented to aid in prevention of XSS attacks.

Although the “X-XSS-Protection” header is being deprecated as time passes, I would still recommend implementing this header for better XSS protection. In addition, this would allow your website to continue being cross browser compatible as well as offering security whilst using legacy browsers such as IE. I would recommend the following implementation for this header:

X-XSS-Protection: 1; report=

Similar to Boolean operations, implementing the header with “0” will disable the XSS filter, whereas the value “1” will enable the XSS filter. The “report” directive allows the browser to send a report to the server defined in this directive if an XSS attempt is detected. Finally, the directive “mode=block” can be implemented to prevent the webpage from loading if an XSS attempt is detected. I would not recommend implementing the “mode=block” directive, as it could affect the availability of your website.

Content-Security-Policy

The “Content-Security-Policy” (CSP) header defines the resources that are allowed to load on webpages. CSP headers are highly configurable to allow flexibility for websites and due to this reason, implementing this can be a challenging task due to its complex mechanisms. However, an appropriately implemented CSP could aid in preventing most forms of XSS attacks. For the purpose of staying on topic for this blogpost, I will only provide a brief description of CSP headers. In order to fully understand every aspect of CSP, a dedicated article will be required. Luckily for us, Mozilla has already done that and it is available here.

CSP headers should be customized to fulfill the requirements of each website and for this reason, it should be somewhat different for every application. As such, I will only be providing an example, as shown below:

Content-Security-Policy: default-src 'self'; script-src safe.scripts.com; img-src *;
object-src source1.jjopentester.com *.cdn.jjopentester.com; report-uri https://csp.jjopentester.com;

Some explanations:

  • default-src ‘self’ is defined to act as a fallback location in the case of missing alternate fetch directives. Although unlikely, this tells the browser to only load resources that are hosted on the same domain as the website.
  • script-src defines the URIs of trusted scripts. In this case, whitelisting the domain “safe.scripts.com” and allowing scripts from that domain to load on a webpage.
  • img-src defines the URIs allowed to include images on the webpage. Images are generally safe to allow inclusion from any domains, and the wildcard asterisk character can be used to configure this.
  • object-src is used to define trusted URIs hosting objects, such as plugins.
  • report-uri is used to define the server where reports should be sent for violations of CSP policies. Web browsers that support this directive will send a CSP violation report to a server defined via HTTP POST. This can be useful in detecting active attempts of XSS attacks on your website.

There are also some other directives such as “https:”, which restricts the resources to load only via HTTPS. I would say that this should ideally be implemented; however, many resources needed by websites out there are HTTP only. Forcing the resources to load only via HTTPS could potentially break your website and affect availability. As such, I would recommend thorough investigation and determine whether the scripts you require for your website is available via HTTPS before implementing this directive.

Google has a reliable CSP checker, where you can test your configuration prior to implementing them on your production websites.

Conclusion

Achieving better security for your websites do not have to be costly. In my experience, low hanging fruits like HTTP security headers are easy to implement and can go a long way in securing the data stored on your website.

We are not saying that these configurations are must haves for your website. You will need to evaluate what your website does, and implement these headers accordingly. Low cost is still cost. If you have a simple, static website that does not do much processing, and does not have much injection points for attackers, consider hand picking a few of the HTTP security headers above to implement. Some of them are freely available, and can be configured on your website’s administrative control panel.

Note that you should not rely solely on implementing these headers to protect your website. There are many more factors and possibilities that could lead to a compromise of your website and the data it stores. As always, do not hesitate to get in touch with us and we can get your website fully tested!

One Response

  1. This gave me an idea how I should test for vulnerabilities on browser, really nice insights for pentester. Thank you !

Leave a Reply

Your email address will not be published. Required fields are marked *