Practical Introduction to Web-Security with Angular and Nginx (Part 2)

Philip Lysenko
8 min readAug 11, 2018

In the previous part we configured a basic Angular and Nginx setup in a Docker container, including configuration for HTTPS. In this part we want to learn about Man-In-The-Middle-Attacks which HTTPS protects us against and strengthen our HTTPS configuration.

Revision

You can find the result code at the point where we left off here: https://github.com/philly-vanilly/angular-nginx/tree/fbf04e9acdc60da57d4d24d9b748bea091a123e7

If something doesn’t work for you, please check out the last part again:

At least you should remember these terminal commands from it:

docker build -t angular-nginx . && docker run -p 80:80 -p 443:443 -it angular-nginx
httpobs-local-scan --http-port 80 --no-verify localhost

HSTS

In the previous part we have forced all requests to be redirected to a second server that only serves over HTTPS (e.g. with TLS encryption enabled). So are we safe from the man in the middle now? Not quite yet. One scenario to be aware of is that a user calls the non-encrypted-version of your site and an attacker (like an evil-minded WiFi host) intervenes before your own server can redirect him to HTTPS safe-space. This actually happens a lot, since most Internet users just input a domain-name in the address-bar, which then could be resolved to a non-TLS endpoint, unless the user has browser-plugins like HTTPS-Everywhere installed.

What the attacker could do now is to make requests to your real website over HTTPS (since you don’t serve without TLS, remember?) and forward it to the user over HTTP. Many users would see no difference as the served HTML and Javascript would be the same and only the https:// in the URI would be missing. This way the attacker can easily read the communication between the user and the real server. But he could even go a step further and alter the served website in any way he wants, from inserting subtle advertisement to self-executing malicious scripts. This attack is called SSL-stripping.

Luckily, web-devs like us can use a header called HSTS (Https Strict Security Policy). It simply forbids the browser to make calls to a known website without SSL/TLS. To enable HSTS, add this to your nginx.conf

Note: I will add this and other configurations to the SSL-server-block, but you can apply it to both servers by moving them to the surrounding http-block. The Observatory is satisfied as long as the SSL-server is secure.

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

With max-age set to 12 months (the Observatory wants at least 6) a browser will call your website exclusively over https for one year since its last visit.

Be aware, HSTS-settings are saved in each of your user’s browsers separately, so if you want to get rid of TLS, you will need to tell your customers to clear their browsers HSTS settings or wait for max-age.

Another thing to keep in mind is that HSTS only works if the user visited your website before. If he is a first-time visitor, an attacker still might strip TLS/SSL by applying redirection before your server can. While this is not required to pass the audit, to prevent this attack, you can preload your website’s HSTS configuration directly into the user’s browsers, provided they support this feature. To do so, submit your HSTS configuration at https://hstspreload.org/ and use the preload flag:

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

Keep in mind, this change is even harder to revert than regular HSTS, so make sure you will be able to provide HTTPS for the duration of max-age. Currently there are around 50.000 domains using this service:

Referrer-Policy

When you click a link to another website, a “Referer” header with the origin URL is usually sent in the request in order to let the destination website know where the user came from.

Think of Referer as the sender’s address on a letter.

The Referer-header is the main source of information for Google Analytics (they do have a few other hacks up their sleeves though, in case it’s missing) and its primary use-case is to help website-owners to optimize their SEO. But it is also sometimes used against “bandwidth-stealing”, allowing requests to resources only to allowed sources, thus preventing embedding images on other websites. But most of the times the Referer is optional and usually URLs on the Internet can be called from the browser’s address-bar without the header being set.

Now because URLs can contain sensitive information (http://example.com/do-i-have-hemorrhoids?user=johndoe) transmitting it to another website is sometimes problematic, especially over an insecure connection where other entities before the endpoint can read that information as well. To prevent this kind of eavesdropping by a party in the middle, the so-called “Referrer-Policy” was introduced.

Note: “Referer” is a misspelling of the word Referrer that found it’s way into the HTTP-standard some time ago. So the browser-set header is officially called Referer but the server-set header controlling/advising the browser is called Referrer-Policy

The Referrer-Policy is set by the source website, instructing the browser to strip parts of the URL (if needed) before redirecting to a destination website.

The good thing about Referrer-Policy is that browsers have a default value when the source website doesn’t specify one explicitly. That default value is “no-referrer-when-downgrade” and it means that Referer is not sent when you go to a HTTP site from a HTTPS one, but all other combinations do send it. E.g:

  • HTTP → HTTP
  • HTTP → HTTPS,
  • HTTPS → HTTPS
  • HTTPS ⇢HTTP (no Referer)

The logic behind it is simple: when going to a HTTP website everybody between the browser and the destination server (e.g. all the men in the middle) can read the traffic and know where the user came from. This is not tragic when coming from an HTTP website, because it is assumed you have nothing to hide anyway if the origin was not secured in the first place. But on a security downgrade this is considered information-leakage.

There are a few other Referrer-Policy options which you might find useful; you can check them out here. For example you can make the browser strip the URL parameters only revealing your protocol and domain. Or you can tell the browser not to send any origin at all, if your site is so private that you don’t even trust the possible destination web-servers.

It is considered good practice to set the header explicitly and the Observatory will give you points for it as it shows you know what you are doing. To pass the audit the default no-referrer-when-downgrade setting is enough:

add_header Referrer-Policy no-referrer-when-downgrade;

HPKP

In the Observatory you can find a check called HPKP. Https Public Key Pinning was a technique that dealt with the unlikely event of a Certificate Authority becoming compromised and issuing forged certificates. With HPKP the browser could recognize forged certificates from a certain CA after encountering real certificates from the same CA in the past on that website. If the signature appeared forged, the user was presented with a warning, the same as for self-signed certificates.

HPKP was mostly pushed by Google, but it was a bit hard to implement and the rest of the Internet was reluctant to adopt it. Some even argued that it was a bad practice. Finally even Google abandoned HPKP in 2017. So while the Observatory still has a HPKP check, it does not add to the audit score and this is why we will skip this one configuration.

Other HTTPS improvements

There are a few other tricks to improve HTTPS with Nginx which I found in this GitHub-thread (also read the comments!). Since the techniques are out of the scope of this beginner-level tutorial and require a bit more knowledge of cryptography, I will not go into detail about them.

For now you can just add this code to your SSL-server-block:

ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_dhparam /etc/ssl/dhparam.pem;ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
resolver 8.8.8.8 8.8.4.4;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/localhost.crt;

For the next step you need OpenSSL, a C++ tool that we installed inside the Docker-image in the first part of this tutorial. If you use a Mac you can get more help on OpenSSL in this tutorial: https://medium.com/@timmykko/using-openssl-library-with-macos-sierra-7807cfd47892

Now you have to generate a dhparam.pem which you can do in your Angular project using this command:

openssl dhparam -out dhparam.pem 2048

As the warning says, it is going to take some time! When finished, make sure it’s copied to the Docker image by adding this to your Dockerfile:

COPY dhparam.pem etc/ssl/dhparam.pem

Do not worry, as explained here the dhparam.pem can be public and you don’t need to generate it inside the Docker container on every deployment.

When the docker container is running you should see the warning that ssl-stapling will be ignored (until you move away from self-signed certificates). If something here didn’t work for you, you can find the final code with a generated dhparam.pem here.

Summary

We successfully strengthened our HTTPS configuration to deal with various Man-In-The-Middle scenarios and increased our audit score. Hooray!

Coming up next…

The next part of the tutorial will be about Cross-Site-Scripting (one of the most common attacks on the Internet) and its main countermeasure, the Content-Security-Policy. There will also be a few other things checked by the observatory; we will finally get a perfect sore! Don’t miss it!

--

--