Security is as important as the website’s content and SEO, and thousands of websites are hacked because of misconfiguration or lack of security. If you are a website owner or security engineer looking to protect your website from attacks by clickjacking, code injection, MIME types, cross site scripting, cookie hijacking etc. then this article will help you in a great way.
Please take a backup of apache/nginx configuration file prior making changes. Some of the headers may not be supported on older browsers, so check out the compatibility before the implementation.
Mod_headers need be enabled in Apache if you are going implement these headers to Apache. You can execute below command in shell with root to enable mod_headers.
~$ sudo a2enmod headers
~$ sudo service apache2 restart
you can use online security header analysing tool to verify the results before and after.
List of Secure HTTP Headers
- HTTP Strict Transport Security
- X-XSS-Protection
- X-Frame-Options
- X-Content-Type-Options
- HTTP Public Key Pinning
- Content Security Policy
- X-Permitted-Cross-Domain-Policies
- Referrer Policy
- Expect-CT
- Feature-Policy
- Cookies with HttpOnly and secure Flags
- Same-Site Cookie Attribute
1. HTTP Strict Transport Security (HSTS)
HTTP Strict Transport Security (HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections, and never via the insecure HTTP protocol. HSTS is an IETF standards track protocol and is specified in RFC 6797. A server implements an HSTS policy by supplying a header (Strict-Transport-Security) over an HTTPS connection (HSTS headers over HTTP are ignored).
HSTS is a critical header and it will be cached in the browser and if site have unsecure resources then it will be blocked which can create issues for you customer. Before implementing this header, you must ensure all your website page is accessible over HTTPS else they will be blocked.
Below are the parameters it takes
Value | Description |
---|---|
max-age=SECONDS | The time, in seconds, that the browser should remember that this site is only to be accessed using HTTPS. |
includeSubDomains | If this optional parameter is specified, this rule applies to all of the site’s subdomains as well. |
preload | This is basically getting your website and or domain on an approved HSTS list that is actually built into the browser. Google officially compiles this list and it is utilized by Chrome, Firefox, Opera, Safari, IE11, and Edge. Submit your site to the official HSTS preload list. |
For HSTS preload you must meet some additional requirements to be eligible.
- The server must have a valid SSL/TLS certificate.
- Redirect all traffic to HTTPS.
- Serve HSTS on the base domain.
- Serve all subdomains over HTTPS, specifically including the www subdomain if it exists.
- Expiry must be at least 1 year (31536000 seconds)
- The includeSubdomains token directive must be specified
- The preload token directive must be specified.
let’s take an example of having HSTS configured for one year including preload for domain and sub-domain.
Apache HTTP Server
You can implement HSTS in Apache by adding the following entry in httpd.conf file or also you can add it in .htaccess
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Nginx
To configure HSTS in Nginx, add the next entry in nginx.conf under server (SSL) directive
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
Microsoft IIS
Launch the IIS Manager and add the header by going to “HTTP Response Headers” for the respective site.
HAproxy
Add below header to haproxy.cfg config file
http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload;"
2. X-XSS-Protection
Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.
An attacker can use XSS to send a malicious script to an unsuspecting user. The end user’s browser has no way to know that the script should not be trusted, and will execute the script. Because it thinks the script came from a trusted source, the malicious script can access any cookies, session tokens, or other sensitive information retained by the browser and used with that site. These scripts can even rewrite the content of the HTML page. For more details on the different types of XSS flaws, see: Types of Cross-Site Scripting.
below are the parameters for X-XSS header
Below are the parameters it takes
Value | Description |
---|---|
0 | Filter disabled. |
1 | Filter enabled. If a cross-site scripting attack is detected, in order to stop the attack, the browser will sanitize the page. |
1; mode=block | Filter enabled. Rather than sanitize the page, when a XSS attack is detected, the browser will prevent rendering of the page. |
1; report=http://mydomain.com/my_report_URI | Filter enabled. The browser will sanitize the page and report the violation. This is a Chromium function utilizing CSP violation reports to send details to a URI of your choice. |
Let’s implement 1;mode=block in the following web servers.
Apache HTTP Server
Add the following entry in httpd.conf of your Apache web server
Header set X-XSS-Protection "1; mode=block"
Nginx
Add the following in nginx.conf under http block
add_header X-XSS-Protection "1; mode=block";
Microsoft IIS
- Open IIS Manager
- Select the Site you need to enable the header for
- Go to “HTTP Response Headers.”
- Click “Add” under actions
- Enter name, value and click Ok
HAproxy
http-response set-header X-XSS-Protection "1; mode=block"
3. X-Frame-Options
X-Frame-Options response header improve the protection of web applications against Clickjacking. By implementing this header, you instruct the browser not to embed your web page in frame/iframe. This has some limitation in browser support, so you got to check before implementing it.
Below are the parameters it takes
Value | Description |
---|---|
deny | No rendering within a frame. |
sameorigin | No rendering if origin mismatch. |
allow-from: DOMAIN | Allows rendering if framed by frame loaded from DOMAIN. |
Let’s take a look at how to implement “sameorigin” so only your domain embeds the web page.
Apache
Add the following line in httpd.conf and restart the webserver to verify the results.
Header always append X-Frame-Options sameorigin
Nginx
Add the following in nginx.conf under server directive/block.
add_header X-Frame-Options "sameorigin";
Microsoft IIS
- Open IIS Manager
- Select the Site you need to enable the header for
- Go to “HTTP Response Headers.”
- Click “Add” under actions
- Enter name, value and click Ok
HAproxy
http-response set-header X-Frame-Options sameorigin
4. X-Content-Type-Options
Prevent MIME types security risk by adding this header to your web page’s HTTP response. Having this header instruct browser to consider files types as defined and disallow content sniffing. There is only one parameter you got to add “nosniff”.
Below are the parameters it takes
Value | Description |
---|---|
nosniff | Will prevent the browser from MIME-sniffing a response away from the declared content-type. |
Let’s add this header to our server.
Apache
You can do this by adding the below line in httpd.conf file
Header set X-Content-Type-Options nosniff
Nginx
Add the following line in nginx.conf file under server block.
add_header X-Content-Type-Options nosniff;
Microsoft IIS
repeat the same as above to add it to IIS HTTP Response Headers field
HAproxy
http-response set-header X-Content-Type-Options nosniff
5. HTTP Public Key Pinning
Minimize the man-in-the-middle (MITM) attacks risk by pinning certificate. This is possible with HPKP (HTTP Public Key Pinning) header.
You can pin the root certificate public key or immediate certificate. At the time of writing, HPKP currently works in Firefox and Chrome and support SHA-256 hash algorithm. Before implement HPKP please read this https://www.chromestatus.com/feature/5903385005916160
Below are the parameters it takes
Value | Description |
---|---|
pin-sha256=”<sha256>” | The quoted string is the Base64 encoded Subject Public Key Information (SPKI) fingerprint. It is possible to specify multiple pins for different public keys. Some browsers might allow other hashing algorithms than SHA-256 in the future. |
max-age=SECONDS | The time, in seconds, that the browser should remember that this site is only to be accessed using one of the pinned keys. |
includeSubDomains | If this optional parameter is specified, this rule applies to all of the site’s subdomains as well. |
report-uri=”<URL>” | If this optional parameter is specified, pin validation failures are reported to the given URL. |
Let’s see HPKP header example
Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
If you need to implement this header on your website, then head to implementation guide written by Scott Helme.
6. Content Security Policy
A Content Security Policy (CSP) requires careful tuning and precise definition of the policy. If enabled, CSP has significant impact on the way browsers render pages (e.g., inline JavaScript disabled by default and must be explicitly allowed in policy). CSP prevents a wide range of attacks, including Cross-site scripting and other cross-site injections.
All browsers don’t support CSP, so you need to verify before implementing it. There are multiple parameters possible to implement CSP, and you can refer OWASP for an idea. However, let’s go through two most used parameters. You can also use online CSP tool to easily generate policy for your website.
Below are the parameters it takes
Directive | Description |
---|---|
default-src | Define loading policy for all resources type in case of a resource type dedicated directive is not defined (fallback). |
script-src | Define which scripts the protected resource can execute. |
The following example of loading everything from the same origin and script from same origin, facebook & google analytics in various web servers.
Apache
Get the following added in httpd.conf file and restart the webserver to get effective.
Header set Content-Security-Policy "default-src 'self'; script-src 'self' *.facebook.com *.facebook.net *.google-analytics.com"
Nginx
Add the following in server block in nginx.conf file
add_header Content-Security-Policy "default-src 'self'; script-src 'self' *.facebook.com *.facebook.net *.google-analytics.com";
Microsoft IIS
do the same as above headers.
HAproxy
http-response set-header Content-Security-Policy "default-src 'self'; script-src 'self' *.facebook.com *.facebook.net *.google-analytics.com"
7. X-Permitted-Cross-Domain-Policies
Using Adobe products like PDF, Flash, etc.? You can implement this header to instruct the browser how to handle the requests over a cross-domain. By implementing this header, you restrict loading your site’s assets from other domain to avoid resource abuse.
Below are the parameters it takes
Value | Description |
---|---|
none | No policy files are allowed anywhere on the target server, including this master policy file. |
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 file names are crossdomain.xml (i.e. URLs ending in /crossdomain.xml) are allowed. |
all | All policy files on this target domain are allowed. |
So let’s go ahead and add this to the headers
Apache
Header set X-Permitted-Cross-Domain-Policies "none"
Nginx
add_header X-Permitted-Cross-Domain-Policies master-only;
Microsoft IIS
Same as above policies
HAproxy
http-response set-header X-Permitted-Cross-Domain-Policies "none"
8. Referrer Policy
The Referrer-Policy HTTP header governs which referrer information, sent in the Referer header, should be included with requests made. There are certain privacy and security benefits. However, not all the options are supported by all the browsers, so review your requirement before the implementation.
Below are the parameters it takes
Value | Description |
---|---|
no-referrer | The Referer header will be omitted entirely. No referrer information is sent along with requests. |
no-referrer-when-downgrade | This is the user agent’s default behavior 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. 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 for 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 from parameters) when performing a a same-origin or cross-origin request. |
Apache
You can add the following if you want to set no-referrer.
Header set Referrer-Policy "no-referrer"
Nginx
Let’s say you need to implement same-origin, so you got to add the following.
add_header Referrer-Policy same-origin;
Microsoft IIS
Do it as mentioned as above.
HAproxy
http-response set-header Referrer-Policy no-referrer
9. Expect-CT
The Expect-CT header is used by a server to indicate that browsers should evaluate connections to the host emitting the header for Certificate Transparency compliance. This project by Google aims to fix some of the flaws in the SSL/TLS certificate system.
Below are the parameters it takes
Value | Description |
---|---|
report-uri | The optional report-uri directive indicates the URL to which the browser should report Expect-CT failures. |
enforce | The optional enforce directive is a valueless directive that, if present, signals to the browser that compliance to the CT Policy should be enforced (rather than report-only) and that the browser should refuse future connections that violate its CT Policy. When both the enforce directive and report-uri directive are present, the configuration is referred to as an “enforce-and-report” configuration, signalling to the browser both that compliance to the CT Policy should be enforced and that violations should be reported. |
max-age | The max-age directive specifies the number of seconds after the reception of the Expect-CT header field during which the browser should regard the host from whom the message was received as a Known Expect-CT Host. |
Apache
Let’s assume you want to enforce this policy, report, and cache for 12 hours then you need to add the following.
Header set Expect-CT 'enforce, max-age=43200, report-uri="https://reportmydomain.com/report"'
Nginx
What if you want to report and cache for 1 hour?
add_header Expect-CT 'max-age=60, report-uri="https://reportmydomain.com/report"';
Microsoft ISS
Same as above
HAproxy
http-request set-header Expect-CT 'enforce, max-age=43200, report-uri="https://reportmydomain.com/report"'
10. Feature-Policy
The Feature-Policy header allows you to selectively enable and disable use of various browsers features and APIs. With help of this headers you define what all kind of controls are allowed or blocked for your web application.
Below are the parameters it takes
Value | Description |
---|---|
accelerometer | Controls access to accelerometer sensors on the device. |
ambient-light-sensor | Controls access to ambient light sensors on the device. |
autoplay | Controls access to autoplay through play() and autoplay. |
camera | Controls access to video input devices. |
encrypted-media | Controls whether requestMediaKeySystemAccess() is allowed. |
fullscreen | Controls whether requestFullscreen() is allowed. |
geolocation | Controls access to Geolocation interface. |
gyroscope | Controls access to gyroscope sensors on the device. |
magnetometer | Controls access to magnetometer sensors on the device. |
microphone | Controls access to audio input devices. |
midi | Controls access to requestMIDIAccess() method. |
payment | Controls access to PaymentRequest interface. |
picture-in-picture | Controls access to Picture in Picture. |
speaker | Controls access to audio output devices. |
usb | Controls access to USB devices. |
vibrate | Controls access to vibrate() method. |
vr | Controls access to VR displays. |
Apache
Let’s say you need to disable the full screen feature and to do so; you can add the following in httpd.conf or apache2.conf.
Header always set Feature-Policy "fullscreen 'none' "
It is also possible to add multiple features in a single line.
Header always set Feature-Policy "fullscreen 'none'; microphone 'none'"
Nginx
Let’s take another example – disable geolocation, camera and speaker feature.
add_header Feature-Policy "geolocation 'none'; camera 'none'; speaker 'none';";
HAproxy
http-request set-header Feature-Policy "fullscreen 'none'; microphone 'none'"
11. Cookies with HttpOnly and secure Flags
You can mitigate most common XSS attacks using HttpOnly and Secure flag with your cookie. Without having HttpOnly and Secure flag in the HTTP response header, it is possible to steal or manipulate web application session and cookies.
t’s better to manage this within the application code. However, due to developer’s unawareness, it comes to Web Server administrators.
Apache
Ensure you have mod_headers.so enabled in Apache HTTP server. Add following entry in httpd.conf
Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
Above entry will add HttpOnly & Secure irrespective to it is already set or not. You can use below code to set HttpOnly;Secure only if it is missing.
Header always edit Set-Cookie "(?i)^((?:(?!;\s?HttpOnly).)+)$" "$1; HttpOnly"
Header always edit Set-Cookie "(?i)^((?:(?!;\s?secure).)+)$" "$1; secure"
12. Same-Site Cookie Attribute
Additionally you can use the Same-Site Cookie Attribute to Prevent CSRF Attacks. Thanks to a new cookie attribute, that Google Chrome started supporting on the 29th of March, and other the popular browsers followed, there is now a solution. It is called the Same-Site cookie attribute.
Setting a Same-Site attribute to a cookie is quite simple. It consists of adding just one instruction to the cookie. Simply adding ‘SameSite=Lax’ or ‘SameSite=Strict’ is enough!
Below are the parameters it takes
Value | Description |
Lax | In lax mode, some cross-site usage is allowed. Specifically if the request is a GET request and the request is top-level. Top-level means that the URL in the address bar changes because of this navigation. This is not the case for iframes, images or XMLHttpRequests. |
strict | In the strict mode, the cookie is withheld with any cross-site usage. Even when the user follows a link to another website the cookie is not sent. |
SameSite=None: Deprecate and remove the use of cookies with the SameSite=None attribute but without the Secure attribute. Any cookie that requests SameSite=None but is not marked Secure will be rejected.
Apache
In order to set this in apache you can add following in httpd.conf/virtualhost/.htaccess
Header always edit Set-Cookie (.*) "$1; SameSite=Lax"
Note : if you are adding these headers to the Apache / Nginx or Microsoft IIS configs then don’t forget to restart the web server.
If you are using Apache web server then you can add these headers to the .htaccess file also. below is a snippet for adding all above headers to htaccess.
<ifModule mod_headers.c>
Header always edit Set-Cookie (.*) "$1; SameSite=Lax"
Header always edit Set-Cookie "(?i)^((?:(?!;\s?HttpOnly).)+)$" "$1; HttpOnly"
Header always edit Set-Cookie "(?i)^((?:(?!;\s?secure).)+)$" "$1; secure"
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always append X-Frame-Options sameorigin
Header always set X-Content-Type-Options nosniff
Header set Content-Security-Policy "default-src 'self'; script-src 'self' *.facebook.net *.facebook.com *.onesignal.com *.google-analytics.com 'unsafe-inline';"
Header always set X-Permitted-Cross-Domain-Policies "none"
Header always set Referrer-Policy "no-referrer-when-downgrade"
Header always set Feature-Policy "fullscreen 'none'; microphone 'none'"
</ifModule>
Securing a website is challenging, and I hope by implementing the above headers, you add a layer of security.