Web Application Security

Security Headers

Posted on October 26, 2016 as Web Security. 5 minutes read.

Introduction

Today we're going to start with Web Security - in particular I want to discuss security headers - small steps to keep your web application more secure. Without wasting your time, let's move to the content.

Specify the doctype

But why is it so important and how can it improve security of my web application?

Answer to this is quite easy, without the specified doctype web browser will try to guess the type of the document based on the content of the website. Sometimes it may guess good, but sometimes, in the worst case, browser can generate our document in so called Quirks Mode. Goal of quirks mode is to preserve the backwards compatibility with times, where web was just starting. As you may think, this may lead to data leaks, or even make the site vulnerable to XSS (even if it was coded properly).

Also remember that you don't have to write older versions of doctype like in HTML4:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

In HTML5 you only have to write:

 <!DOCTYPE HTML>

Easy, right?

Subresource Integrity

Lots of web applications are based on the external libraries or frameworks like AngularJS, jQuery, BootStrap etc and loads of web developers instead of downloading them into the server, often link them from CDN's (Content Delivery Network) of creators, from where the script is downloaded and executed during the process of rendering webpage. Here's the example of linking AngularJS framework:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>

But what if someone attacks the ajax.googleapis.com and changes the script into more malicious one, for example putting browser exploit? Then our vistiors are also attacked, and it's our goal to make it impossible.

To prevent these situtations, Subresource Integrity allows us to add additional attribute to the script or link tags, where we should enter encoded in Base64 hash (SHA-256, SHA-384, SHA-512) for the external file. Then when the hash doesn't match the hash of the downloaded script, browser won't run it. In our example SRI script will look like this:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js" integrity="sha384-V6/dyDFv85/V/Ktq3ez5B80/c9ZY7jV9c/319rqwNOz3h9CIPdd2Eve0UQBYMMr/"></script>>

Try this site to generate SRI hash: SRI Hash Generator

X-XSS-Protection

Google Chrome and Internet Explorer have built-in filter preventing Reflected XSS attacks. They work quite easily, checking, if there are HTML tags in the HTTP query, or even different fragments of JavaScript code, and then if this code also shows up in the answer. If yes, then the browser assumes that this is XSS attack, and blocks this piece of code.

Both in IE and Chrome, you can enable the filters using X-XSS-Protection header.

  • X-XSS-Protection: 0 - XSS filter is disabled and the browser won't try to detect XSS attacks
  • X-XSS-Protection: 1 - XSS filter is enabled - and this is the default option. It blocks the piece of code suspected for being XSS payload.
  • X-XSS-Protection: 1; mode=block - XSS filter, which after detecting XSS attack, will stop rendering the web page.

The best option to choose would be the last one, since it doesn't only blocks XSS attacks, it also lets us dodge vulnerabilities described in X-XSS-Nightmare written by Msato Kinugawy.

X-Content-Type-Options

This header disables the guessing MIME type of the site, by the browser. It also protects us from uploading files different than they should be (JavaScript file as a photo etc). Example:

We have the web application allowing users to upload images. Attacker after uploading malicious .png file, tries to change the source of the script into his malicious script.

<script src="http://www.example.com/uploads/malicious.png”></script>

But the X-Content-Type-Options won't allow this operation, since image (MIME type image/png) doesn't match the script type. X-Content-Type-Options has only one possible value: nosniff

X-Content-Type-Options: nosniff

X-Frame-Options

X-Frame-Options header was introduced as an response to clickjacking attacks, but is also used to protect from many different kinds of attacks. This header reduces the number of domens, where our web application can be put into frame, iframe or object tags.

  • X-Frame-Options: Deny - web page connot be put into frames on any different sites.
  • X-Frame-Options: SameOrigin - web page can only be put into frames on the the webpages originating from the same domain.
  • X-Frame-Options: Allow-From url - web page can be put only on specified domain.

Best option would be SameOrigin or Deny, unless you want to share any widgets.

HttpOnly/Secure Flags

For HTTP cookies we can add 2 flags making them more secure - HttpOnly and Secure.

HttpOnly flag lets us avoid one of the most popular result of XSS attacks - stealing session cookies. Attackers payload can be done using JavaScript document.cookie and sending it to his server, but with HttpOnly cookie will be only sent in queries to server, it won't show up using document.cookie

Secure flag guarantees us that, when application works both in HTTP and HTTPS, it will only send cookies using HTTPS.

Here's and example of Set-Cookie, with both flags:

Set-Cookie: PHPSESSID=el4ukv0kqbvoirg7nkp4dncpk3; HttpOnly; Secure

Setting up flags for session cookies depends on used technology, but specific instructions should be presented in documentation.

Strict-Transport-Security

Last but not least Strict-Transport-Security header comes handy, when we're building web application, that should never be runned with HTTP. After defining this header, we gain 2 mechanisms protecting us from man in the middle attacks.

We are sure that web browser will never send queries using HTTP protocol.

When negotiation SSL connection results in an error (ex invalid certificate), browser won't let user to accept such certificate.

While implementing Strict-Transport-Security header, it's essential to enter max-age parameter, saying how long should the header be significant (in seconds). After that time there will be possibility to once again perform queries using HTTP protocol.

Example of such header valid for one year:

Strict-Transport-Security: max-age=31536000

I hope that after this read, you gained better understanding of secure headers. In the future I'll write about Content-Security-Policy, but it is material for a whole new post, so keep tuned ;)

Keep learning and stay safe!

~ W3ndige