Categories

Security HTTP Headers

Posted on: September 13, 2015 by Dimitar Ivanov
Overview

Last few years a bunch of new HTTP headers were added to the web platform. The purpose of this blog post is to discuss the most critical headers from a security perspective.

X-Frame-Options

This http header helps avoiding clickjacking attacks. Browser support is as follow: IE 8+, Chrome 4.1+, Firefox 3.6.9+, Opera 10.5+, Safari 4+. Posible values are:

deny
browser refuses to display requested document in a frame
sameorigin
browser refuses to display requested document in a frame, in case that origin does not match
allow-from: DOMAIN
browser displays requested document in a frame only if it loaded from DOMAIN
// Raw header
X-Frame-Options: sameorigin

// How to send the response header with PHP
header("X-Frame-Options: sameorigin");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-Frame-Options "sameorigin"
</IfModule>

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-Frame-Options", "sameorigin");
    next();
});

X-Frame-Options

X-XSS-Protection

Use this header to enable browser built-in XSS Filter. It prevent cross-site scripting attacks. X-XSS-Protection header is supported by IE 8+, Chrome and Safari. Available directives:

0
disables the XSS Filter
1
enables the XSS Filter. If a cross-site scripting attack is detected, in order to stop the attack, the browser will sanitize the page.
1; mode=block
enables the XSS Filter. Rather than sanitize the page, when a XSS attack is detected, the browser will prevent rendering of the page.
// Raw header
X-XSS-Protection: 1; mode=block

// How to send the response header with PHP
header("X-XSS-Protection: 1; mode=block");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-XSS-Protection "1; mode=block"
</IfModule>

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-XSS-Protection", "1; mode=block");
    next();
});

X-Content-Type-Options

This http header is supported by IE and Chrome, and prevents attacks based on MIME-type mismatch. The only possible value is nosniff. If your server returns X-Content-Type-Options: nosniff in the response, the browser will refuse to load the styles and scripts in case they have an incorrect MIME-type. The list with available MIME-types for styles and scripts is as follow:

Styles
  • text/css
Scripts
  • application/ecmascript
  • application/javascript
  • application/x-javascript
  • text/ecmascript
  • text/javascript
  • text/jscript
  • text/x-javascript
  • text/vbs
  • text/vbscript
// Raw header
X-Content-Type-Options: nosniff

// How to send the response header with PHP
header("X-Content-Type-Options: nosniff");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
</IfModule>

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("X-Content-Type-Options", "nosniff");
    next();
});

So if you try to load for example a HTML document as external script resource (the src attribute of HTMLScriptElement), the browser will refuse it.

X-Content-Type-Options

Strict-Transport-Security

To take advantage of this security header, the current webpage must be accessed over HTTPS. In this case the Strict-Transport-Security header force secure connections to the server. This prevents losing session data stored in cookies. Also prevents users to access website in case the server's TLS certificate is not trusted. Browser support: IE 11+, Chrome 4+, Firefox 4+, Opera 12+, Safari 7+. Accepts following directives:

max-age
Required. The number of seconds that browser should force the connection over HTTPS.
includeSubDomains
Optional. If present, tells to the browser that the policy applies to current host and to all host's subdomains.
// Raw header
Strict-Transport-Security: max-age=31536000
// or
Strict-Transport-Security: max-age=31536000; includeSubDomains

// How to send the response header with PHP
header("Strict-Transport-Security: max-age=31536000");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set Strict-Transport-Security "max-age=31536000"
</IfModule>

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("Strict-Transport-Security", "max-age=31536000");
    next();
});

Content-Security-Policy

This header could affect your website in many ways, so be careful when using it. The configuration below allows loading scripts, XMLHttpRequest (AJAX), images and styles from same domain and nothing else. Browser support: Edge 12+, Firefox 4+, Chrome 14+, Safari 6+, Opera 15+

Few notes: IE 10 and 11 supports CSP through the X-Content-Security-Policy header; Safari 5.1 supported through the X-Webkit-CSP header.

// Raw header
Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';

// How to send the response header with PHP
header("Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';");

// How to send the response header with Apache (.htaccess)
<IfModule mod_headers.c>
    Header set Content-Security-Policy "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';"
</IfModule>

// How to send the response header with Express.js
app.use(function(req, res, next) {
    res.header("Content-Security-Policy", "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';");
    next();
});

Access-Control-Allow-Origin

The Access-Control-Allow-Origin is part of the cross-origin resource sharing specification which we discussed recently.

Public-Key-Pins

The Public Key Pinning Extension for HTTP (HPKP) is a security feature that tells a web client to associate a specific cryptographic public key with a certain web server to prevent man-in-the-middle attacks with forged certificates. Available directives are:

pin-sha256
A Base64 encoded Subject Public Key Information (SPKI) fingerprint.
max-age
The time, in seconds, that the user-agent should remember the host as a Known Pinned Host.
includeSubDomains
An optional directive that signals to the user-agent that the Pinning Policy applies to this Pinned Host as well as any subdomains of the host's domain name.
report-uri
An optional directive that indicates the URI to which the user-agent should report Pin Validation failures.
// Raw
Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; max-age=604800; includeSubDomains; report-uri="https://example.net/pkp-report"

// PHP
header('Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; max-age=604800; includeSubDomains; report-uri="https://example.net/pkp-report"');

// Apache
<IfModule mod_headers.c>
    Header set Public-Key-Pins "pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; max-age=604800; report-uri=\"https://example.net/pkp-report\""
</IfModule>

// nginx
add_header Public-Key-Pins "pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"; max-age=604800";

// Express.js
app.use(function(req, res, next) {
    res.header("Public-Key-Pins", 'pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; max-age=604800; includeSubDomains');
    next();
});
Conclusion

Big players as Google+, Facebook, Twitter, LinkedIn use the above HTTP headers as an additional layer on a defence of their architecture. So it's strongly recommended the use of security HTTP headers to make your website safer and resist of attacks.

Make your website more secure by using the HTTP Headers for Wordpress, and never face a cross-origin issue again. Oh yes, it's FREE.
See also
References
Share this post

Thanks so much for reading! If you have questions about HTTP security please drop a comment below. Don't forget to share too.


11 Comments

Aditya
Thanks to this blog entry. You solve all the query my mind about header security about most successful companies use this type of security.
Dimitar Ivanov
Thanks, Aditya. It's great to know you find my article about HTTP security useful.
Raj
Hi Dimitar,

Thanks for such expert blog post. I need to implement all these headers in one of my PHP website. Can you please let me know how I can do this? If I send response header only via apache (.htacces) then would it be sufficient ? Or I need to implement other options as well.

Thanks.
Dimitar Ivanov
Hi Raj,

The server has to send these headers, so there is no matter what you have used, e.g. server-side language (PHP, Ruby, Python) or server configuration file (.htaccess)
Raj
Thanks, Dimitar.

It means the examples above are showing different ways of doing this and we only need to integrate only one way.

Thanks again.
sanju
Hi
but how to use this for java script and jsp
Dimitar Ivanov
Hi Sanju,

To sent a header In JSP you can use the setHeader method:

response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("X-Content-Type-Options", "nosniff");
khaleel
Hi Dimitar,
My application is in IIS,coldfusion,javascript ,jquery and sql server when i ran IBM app scan tool following issues reported
1. Missing "Content-Security-Policy" header
2. Missing "X-Content-Type-Options" header
3. Missing "X-XSS-Protection" header
4. Missing HTTP Strict-Transport-Security Header
Can you please let me know how to resolve in html,Javascript and iis
Craig
Hi Dimitar, thanks for the article. I have been using these headers for a while, but something completely passed me by - My apps use https and one day using fiddler I was initially surprised not to see my headers, but of course they are http. Does this mean I cannot have the same protection using https, or in some way do they still work in https?
Dimitar Ivanov
Hi @Craig,
Fiddler disabled the HTTPS decryption by default. To enable it, do following:

1. Click Tools > Fiddler Options.
2. Click the HTTPS tab. Ensure the Decrypt HTTPS traffic checkbox is checked.
Craig
Hi Dimitar, many thanks for your help. After setting Fiddler to decrypt, I can now see my security headers. Many thanks for your help. Best Regards Craig

Leave a comment

Captcha