Essential HTTP Headers for Securing Your Web Server
Oct 22, 2018 • Satyam Singh
In this article we discuss the most important HTTP headers that you should configure on your web server in order to improve its security.
We will understand what is the role of each header and what attacks can be implemented to take advantage of its misconfiguration.
Here are the types of interesting HTTP headers that we will discuss:
- Server headers that protect against attacks
- HTTP Strict Transport Security
- Content Security Policy
- Server headers that leak information
Background on HTTP headers
HTTP headers are used by the client and web server to share information as part of the HTTP protocol. When we enter a URL in the address bar of the browser or click on any link, the web browser sends a HTTP request containing client headers while the HTTP response contains server headers.
Here is such a HTTP request-response pair when calling Google’s web page:
There are tens of HTTP headers and explaining them is not the purpose of this article. However, you can find a good reference and details for each header on Mozilla’s HTTP Headers page.
We will talk though about the HTTP server headers that have a security impact.
1. HTTP Strict Transport Security (HSTS)
HTTP Strict Transport Security instructs the browser to access the web server over HTTPS only. Once configured on the server, the server sends the header in the response as
Strict-Transport-Security. After receiving this header, the browser will send all the requests to that server only over HTTPS. There are 3 directives for the HSTS header:
- Max-age: This defines a time for which the web server should be accessed only through HTTPS. The default value of this header is 31536000 seconds. This is the maximum age (time) for which HSTS is valid. The server updates this time with every new response hence preventing it from expiring.
IncludeSubDomains: This applies the control over subdomains of the website as well.
Preload: Preload list is the list of the websites hardcoded into Google Chrome browser which can communicate via HTTPS only. The owner of the website can submit its URL to be included in the preload list. This list is maintained by Google but other browsers also use it. The preload list can be found here: https://chromium.googlesource.com/chromium/src/+/master/net/http/transport_security_state_static.json
Without HSTS enabled, an adversary can perform a man-in-the-middle attack and steal sensitive information from the web session of a user. Imagine a scenario where a victim connects to an open Wi-Fi which is actually in the control of an attacker. Accessing a website over HTTP would allow the attacker to intercept the request and read the sensitive information. (The site is on HTTPS but user accesses it with HTTP which later gets redirected to HTTPS). If the same user had accessed the website earlier, the HSTS details recorded in the browser would have caused the connection to be made over HTTPS automatically.
2. Content Security Policy
Content Security Policy is used to instruct the browser to load only the allowed content defined in the policy. This uses the whitelisting approach which tells the browser from where to load the images, scripts, CSS, applets, etc. If implemented properly, this policy prevents exploitation of Cross-Site Scripting (XSS), ClickJacking and HTML injection attacks.
The name of the header is
Content-Security-Policy and its value can be defined with the following directives:
img-src. They specify the sources from where the browser should load those types of resources (scripts, media, etc).
Here is an example setting:
Content-Security-Policy: default-src 'self'; media-src media123.com media321.com; script-src script.com; img-src *;
This is interpreted by the browser as:
default-src 'self': Load everything from the current domain
media-src media123.com media321.com: Media can only be loaded from media1.com and media2.com
script-src script.com: Script can only be loaded from script.com
img-src *: Image can be loaded from anywhere in the web
Content-Security-Policy header correctly set for dropbox.com:
Content-Security-Policy header not set for apple.com:
More information about Content Security policy can be found on Mozilla’s website.
Access-Control-Allow-Origin is a CORS (Cross-Origin Resource Sharing) header. This header allows the defined third party to access a given resource. This header is a workaround for restrictions posed by the Same Origin Policy which doesn’t allow two different origins to read the data of each other.
For example if Site ABC wants to access a resource of Site XYZ, Site XYZ will respond with an
Access-Control-Allow-Origin header with the address of Site ABC. In this way Site XYZ is telling the browser who is allowed to access its content:
Access-Control-Allow-Origin is weakly configured, an attacker can read the data from the target website by using another third party website. Many developers use a wildcard for
Access-Control-Allow-Origin header which allows any website to read the data from their website.
The cookie values set by the application are sent by the server in the
Set-Cookie header. After receiving this header, the browser will send the cookies with every HTTP request in the
The HTTP cookies can often contain sensitive information (especially the session cookies) and they need to be protected against unauthorized access.
The following attributes can be set for securing the cookies:
Secure: A cookie set with this attribute will only be sent over HTTPS and not over the clear-text HTTP protocol (which is susceptible to eaves-dropping).
Secure are set correctly for dropbox.com:
Cookie security attributes are not set for boeing.com:
This header is used to protect the user against ClickJacking attacks by forbidding the browser to load the page in an iframe element. There are 3 directives for
- X-Frame-Options: DENY - This will not allow the page to be loaded in a frame on any website.
- X-Frame-Options: sameorigin - This will allow the page to be loaded in a frame only if the origin frame is same i.e. A page on www.site.com will load in a frame only if the parent page on which the frame is being loaded has the same origin (www.site.com)
- X-Frame-Options: allow-from uri - The frame can only be displayed in a frame on the specified domain/origin.
An adversary could trick a user to access a malicious website which will load the target application into an invisible iframe. When the user clicks on the malicious application (ex. a web-based game), the clicks will be ‘stolen’ and sent to the target application (Clickjacking). As a result, the user will click on the legitimate application without his consent, which could result in performing some unwanted actions (ex. delete an account, etc).
X-Frame-Options header implemented correctly to deny frame loading for dropbox.com:
X-Frame-Options header not implemented on ibm.com:
This header is designed to protect against Cross-Site Scripting attacks. It works with the XSS filters used by the modern browsers and it has 3 modes:
X-XSS-Protection: 0; - Value 0 will disable the XSS filter
X-XSS-Protection: 1; - Value 1 will enable the filter, in case the XSS attack is detected, the browser will sanitize the content of the page in order to block the script execution.
X-XSS-Protection: 1; mode=block - Value 1 used with block mode will prevent the rendering of the page if an XSS attack is detected.
X-XSS-Protection header implemented correctly on linkedin.com:
X-XSS-Protection header missing on instagram.com:
This response header is used to protect against MIME sniffing vulnerabilities. So what is MIME Sniffing? MIME sniffing is a feature of the web browser to examine the content of the file being served. It works as follows:
A web browser requests a file. The server sends a file with the HTTP header Content-Type set.
The web browser ‘sniffs’ the content of this file in order to determine the file format.
Once done with the analysis, the browser compares its result with the one sent by the server. If there is a mismatch, the browser uses the identified format.
This may result in a security vulnerability. How?
- An application allows the user to upload an image file and validates its extension
- A user uploads an image file with jpg or png extension but this file contains malicious HTML code as well
- The browser renders the file with HTML which contains the code and executes in the browser
By setting the header
X-Content-Type-Options to nosniff, the browser will no longer ‘sniff’ the content of the file received but use the value from the Content-Type header. This header is specific to IE and Chrome browsers.
This header can be used along with two more headers in order to enhance the security.
- Content-Disposition: It forces the browser to display a pop up for downloading the file pentest.html.
Content-Disposition: attachment; filename=pentest.html
- X-Download-Options: When this header is set to noopen, the user is forced to save the file locally first before opening instead of opening the file directly in the browser
X-Content-Type-Options header implemented correctly for linkedin.com:
X-Content-Type-Options header is not implemented on instagram.com:
This header contains information about the backend server (type and version). For instance, the screenshot below shows that the web server that runs Nike’s web page is
An adversary with this knowledge may look for vulnerabilities specific to the version 9.4.8 of Jetty. This information can be found in public databases such as:
You just need to search for the specific product and version. Here are the vulnerabilities affecting the Jetty web server:
The server information can be masked by re-configuring the web server. For example, here is a good configuration on Linkedin’s website (the server name was modified to "Play"):
Contains the details of the web framework or programming language used in the web application. For instance, the web application at https://msc.mercedes-benz.com was built with
PHP 7.1.22 and is hosted with
As the name suggests, it shows the version details of the ASP .NET framework. This information may help an adversary to fine-tune its attack based on the framework and its version.
Here is such an example header from the server at http://demo.testfire.net
HTTP headers can be configured on the server to enhance the overall security of the web application. These headers do not make the application more secure but they prevent exploitation of the potential vulnerabilities of the application.
- Exploiting Magento SQL Injection with Sqlmap
- How to do a Basic Website Vulnerability Assessment with Pentest-Tools.com
- Analysis of a WordPress Remote Code Execution Attack
- Common SQL Injection Attacks
- Exploiting OGNL Injection in Apache Struts
- Inside Nmap, the world’s most famous port scanner
- Pentest report writing in 5 minutes (Defcamp 2018 talk)
- Essential HTTP Headers for Securing Your Web Server
- 5 Practical Scenarios for XSS Attacks
- All posts ...