Pre-loading HSTS for sibling domains through this one weird trick

The vast majority of websites now support encrypted connections over HTTPS. This prevents eavesdroppers from monitoring or tampering with people’s web activity and is great for privacy. However, HTTPS is optional, and all browsers still support plain unsecured HTTP for when a website doesn’t support encryption. HTTP is commonly the default, and even when it’s not, there’s often no warning when access to a site falls back to using HTTP.

The optional nature of HTTPS is its weakness and can be exploited through tools, like sslstrip, which force browsers to fall back to HTTP, allowing the attacker to eavesdrop or tamper with the connection. In response to this weakness, HTTP Strict Transport Security (HSTS) was created. HSTS allows a website to tell the browser that only HTTPS should be used in future. As long as someone visits an HSTS-enabled website one time over a trustworthy Internet connection, their browser will refuse any attempt to fall back to HTTP. If that person then uses a malicious Internet connection, the worst that can happen is access to that website will be blocked; tampering and eavesdropping are prevented.

Still, someone needs to visit the website once before an HSTS setting is recorded, leaving a window of opportunity for an attacker. The sooner a website can get its HSTS setting recorded, the better. One aspect of HSTS that helps is that a website can indicate that not only should it be HSTS enabled, but that all subdomains are too. For example, planet.wikimedia.org can say that the subdomain en.planet.wikimedia.org is HSTS enabled. However, planet.wikimedia.org can’t say that commons.wikimedia.org is HSTS enabled because they are sibling domains. As a result, someone would need to visit both commons.wikimedia.org and planet.wikimedia.org before both websites would be protected.

What if HSTS could be applied to sibling domains and not just subdomains? That would allow one domain to protect accesses to another. The HSTS specification explicitly excludes this feature, for a good reason: discovering whether two sibling domains are run by the same organisation is fraught with difficulty. However, it turns out there’s a way to “trick” browsers into pre-loading HSTS status for sibling domains.

google chrome hsts warningFirstly, enable HSTS at the parent domain, indicating that it and all subdomains are HSTS enabled. Secondly, include a resource hosted at the parent domain (e.g. an image) in every webpage on its subdomains. Now, a visit to any sibling domain (e.g. planet.wikimedia.org) will trigger a request to the parent domain (wikimedia.org) that has the side-effect of enabling HSTS for the parent domain and every sibling domain (commons.wikimedia.org, donate.wikimedia.org etc.).

This trick will generate another DNS request and HTTPS connection, so for performance reasons, the extra resource shouldn’t block the webpage from being rendered, and it should have a long cache-expiry time. Then, the extra resource shouldn’t affect the time it takes for the webpage to appear, and once the resource has done its job, it won’t be downloaded again. This small overhead seems worth the significant benefit to users, for websites that use sibling domains but aren’t big enough to go in the browser preload list.

Consider, for example, Bentham’s Gaze. The canonical domain for the blog is www.benthamsgaze.org, and other domains redirect to it. As a result, visitors to this blog will have something like the following record in their HSTS database (for Firefox, but other browsers have something similar).

www.benthamsgaze.org^partitionKey=%28http%2Cbenthamsgaze.org%29:HSTS 0 18897 1664295780022,1,1,2

This line means that www.benthamsgaze.org is HSTS enabled (HSTS 0) until timestamp 1664295780022 (i.e. 27 September 2022, a 1-year expiry), and HSTS applies to subdomains too (the second “1” in 1,1,2). However, this record won’t apply to stage.benthamsgaze.org, for example.

To fix this, let’s add a resource at benthamsgaze.org, which will set an HSTS rule applying to both subdomains (www and stage). The resource needs to be static and not block web page rendering, so the favicon seems like a good choice; a 1-pixel image would also work well, or perhaps even a CSS file.

As www.benthamsgaze.org is the canonical domain name, there’s a redirect in place from benthamsgaze.org that prevents us from hosting anything at the parent domain. We need to therefore make an exception for the favicon file by changing the Apache configuration from:
Redirect permanent / https://www.benthamsgaze.org/
to:
RewriteEngine on
RewriteCond "%{REQUEST_URI}" "!^/favicon.ico$"
RewriteRule "^/?(.*)" "https://www.benthamsgaze.org/$1" [L,R=301,NE]

Next, we need to add the HTML header that loads the favicon from benthamsgaze.org. In our WordPress site, we can do this by adding a hook to the child theme:

function hook_favicon() {
?>
<link rel="icon" type="image/vnd.microsoft.icon" href="https://benthamsgaze.org/favicon.ico" />
<?php
}
add_action('wp_head', 'hook_favicon');

Now, when we load www.benthamsgaze.org, we see the parent domain HSTS rule is stored, covering the subdomains www, stage, and any others.

benthamsgaze.org^partitionKey=%28http%2Cbenthamsgaze.org%29:HSTS 0 18897 1664295779759,1,1,2

It’s a simple trick but seems to be effective, and we haven’t seen it proposed elsewhere. We would also encourage you to check your own HSTS local database to see how many different domains carry duplicate HSTS records for their subdomains; this can give you an idea of how widely applicable this technique can be. It may not be a groundbreaking change, but it does add some extra confidence that HSTS is keeping you or your users safe online. Please do let us know in the comments if you’re aware of anyone else using it, spot any problems, or if you have any suggestions for improvements.

 

Photo by Richy Great on Unsplash

Leave a Reply

Your email address will not be published. Required fields are marked *