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:
In HTML5 you only have to write:
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:
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:
Try this site to generate SRI hash: SRI Hash Generator
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.
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.
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-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.
For HTTP cookies we can add 2 flags making them more secure - HttpOnly and Secure.
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:
Setting up flags for session cookies depends on used technology, but specific instructions should be presented in documentation.
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:
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 ;)