Saturday, October 12, 2019

Is your web site secure?




Securing your site has never been more critical, and this entails keeping up with the latest security options. But what does securing a website mean? It means writing modern and secure code and applying server patches regularly, as well as defending against external attacks the server can’t control. That’s where security headers come in. The server sends security headers to the client, and the browser evaluates them, protecting users against a myriad of attacks. I should note here that the ability to receive security headers is dependent on browser support.

HTTP Strict Transport Security (HSTS)

In 2019 all websites had to be secured by HTTPS. As HTTPS certificates have been freely available for a while now, there are no longer any valid excuses for not using them. HTTPS adds an encryption layer, so messages cannot be read by a man in the middle between the server and client.
If a user requests the HTTP version of a page, there are multiple approaches to handling these requests, the most common being responding with a 301 Moved Permanently status. In addition to allowing eavesdropping on requests, HTTP also allows malicious actors tampering responses, meaning users may never be redirected to the secure version of the site. Users may instead be redirected to a malicious website, which is just one example of many bad outcomes that could result from using HTTP.

No STS header HTTP request

Strict Transport Security (STS) header solves many of the problems created by using HTTP. This header tells the browser that it should only use the HTTPS version of the site. But we’ve already seen that one HTTP request is enough for an attack. How is this header the solution then?
By default, an STS header works on the principle of “trust on first use”. This requires an initial secure connection to be able to include an STS header in the response. After there has been a secure connection with STS, then for an amount of time specified by the max-age STS directive the browser will not allow HTTP for the same domain. If there’s an attempt to request the unsecured (HTTP) version of the page, the browser will automatically redirect the request using a 307 Internal Redirect. This redirect occurs before the request reaches the network, thus attackers cannot see or modify the request. This capability also extends to subdomains with the includeSubDomains directive.
Some issues: we still need a successful secured connection before all this can work, and max-age is not infinite. These leave a smaller, but nevertheless existing hole in our defences. Luckily, there’s a third directive preloadwhich enables the HSTS header user to have this policy shipped with the browser itself.
How? Any site wanting to use this option must register to a HSTS preload list. Chromium’s list is used by Chrome and all major browsers, so is the best option. There are certain rules for applying to the list, e.g. having the preloaddirective in the header. Once a domain is accepted, the next version of each browser will include the domain in their list. This is great, because now the browser knows that before any request is made to the site it must use HTTPS. There is no need to “trust on first use”. All major browsers currently support HSTS.


HTTP Public Key Pinning (HPKP)

Using HTTPS is nice, and in most cases it is trustworthy. But what happens if malicious actor uses a valid certificate, which is not the site’s own? This is called a rogue certificate, and gives the attacker the same level of access as if using HTTP. Hijacking HTTPS with this method is far more complicated than hijacking HTTP, so HTTPS is still the best bet for keeping communication secure. HPKP would’ve been another option for tackling this issue. It provides a whitelist of valid certificates (hashes of certificates) for a site. Some instances of real world attacks as well as research by security experts show that HPKP is both a solution and a source of new vulnerabilities, so most major browsers have now dropped support for it.

Content Security Policy (CSP)

Do you want to tell the browser what content (scripts, styles, etc.) can load and how can they behave on your site? CSP lets you do just that. You can whitelist resources so that they can be run or be embedded on your site. CSP has more than 30 directives, each with its own browser compatibility. Most of these directives are supported by major browsers, but it’s worth checking the MDN support list before using a new one. If you don’t want to add a CSP directive manually, you can use a CSP header generator tool which automates the process.

Before highlighting some of the best directives, note that CSP has two major modes to be used in: first there’s CSP which blocks everything not on the whitelist, as expected. This mode while provides safety, can also be the source of much headache when you try to enable your third-party sources one by one, and have a broken site the meantime. CSP-Report-Only on the other hand does all the things CSP can, except it does not block resources, only report any violations found. This comes very handy both when creating the CSP rules, and also when you kind of want a directive, but not too sure if you’d risk to break something if the environment changes.

Fetch directives

These directives define where the specified resources can be loaded from. Resource types include images, fonts, scripts, and many others. The most important resource is default-src which serves as a fallback for all other fetch directives. In case any resource directive is absent, the value provided in default-src will be used. A good start for using fetch directives is to use self as value which disallows cross-domain resources, and then add custom fetch directives for any exceptions. These rules should be the minimum for CSP-Report-Only.

Scripts and styles

Using inline styles (the “style” HTML attribute) is cited as a bad practice, so using style-src self;is a better practice. We can add exceptions here as well, for example use a hash or a nonce.
script-src is also a fetch directive and is one of the most important directives to set correctly. This needs to be strict, but also needs to allow some third parties — Google Analytics for example — to bypass. In this case, using “self” is virtually impossible. An alternative is using a hash, but a hash needs to be updated every time the script changes, which is frequent for third party scripts. Using a nonce (number used once) is probably the best solution. A nonce must be a globally unique cryptographic number, which should be generated and sent every time the server sends a CSP header to the browser. This guarantees the same level of protection as a hash(if we use a nonce that’s hard to guess), but because it is a dynamic number it does not need manual updates.

No comments:

Post a Comment