Find Edge’s HSTS Preload List (Part I)

Xiaoyin Liu
Apr 20, 2018 · 5 min read

In this article, I will discuss how I find out the HSTS preload list of Edge browser. This is not a vulnerability in Edge. I hope you still enjoy reading it. This article has two parts: in Part I, I will discuss how I let Edge generate the list itself by running JavaScript in browser, with the help of Fiddler. If I have time, I will write Part II, in which I will show how to find the list by reverse engineering.

Background
The HTTP Strict Transport Security (HSTS) is designed to mitigate man-in-the-middle attacks by forcing browsers to use HTTPS connections when users visit your websites. HSTS policies can be either set dynamically or preloaded in browsers. To set HSTS dynamically, send a HTTP response header “Strict-Transport-Security: max-age=31536000; [includeSubDomains]”, meaning that in the next 31536000 seconds (1 year), browsers must use HTTPS when connect to this domain. If the optional directive includeSubDomains is set, all its subdomains are forced to use HTTPS too.

The problem with dynamic HSTS policy is that the initial connection to the server is not protected. To fix this problem, Google maintains a HSTS preload list. Developers can submit their domains to the preload list at . This list is hardcoded in the binary files of all major browsers.

Although all browsers’ lists are based on Chrome’s, the latest stable version of different browsers have different hardcoded preload list, because of varied release cycles, and extra requirements. Firefox and Chrome are open sourced, so we can easily know their preload list from the source code. Latest Firefox preload list is available from , and Chrome preload list is available from . Edge is not open sourced, and so far I didn’t find anyone posting the Edge’s list online, so, for curiosity, I decided to find it out myself.

Method
It’s worth mentioning that a limitation of this method is that it only tests the domains listed in Chrome’s preload list, but since all browsers use the same list, so it won’t be too inaccurate. The idea of is that we go through each domain in the Chrome’s list. For each of them, we load it in Edge. If Edge automatically rewrites HTTP to HTTPS, then this domain is preloaded in Edge too. We can detect it in this way: for example, to check example.com, we construct an img element with src=http://example.com/hsts.gif. If it is preloaded, the request sent to the server is HTTPS; otherwise, the request is HTTP. To make these two situations detectable in JavaScript, I use Fiddler proxy to fake the responses locally. If Fiddler sees the request URL is http://example.com/hsts.gif, it responds with a sample gif file. When Edge gets the response, the onload handler is invoked. If Fiddler sees a CONNECT request, this means the URL has been rewritten to HTTPS. In this case, Fiddler resets the CONNECT request, making Edge fire the onerror handler. Then we only need to handle the onload and onerror events in our JavaScript and log accordingly. If onload is fired, it’s not preloaded; if onerror is fired, it is preloaded.

I have posted the full code I used on GitHub. It’s available at . If you want to try it out in your browsers, make sure to set up a proxy with rules detailed in the previous paragraph, and delete browsing history to remove dynamic HSTS entries. If you use Fiddler, just add the following three rules in AutoResponder:

Then open in browsers you want to test. It will take a while for the test to complete.

Results
The reference list I used is .

Here are the results:

  • Total number of HSTS entries in transport_security_state_static.json: 48891
  • Edge on Windows 10 Build 16299.371 with patches up to April 2018: 14843 (+636 without subdomains)
  • Firefox 59.0: 33666 (+1008 without subdomains)
  • Chrome 66.0.3359.117: 45447 (+0 without subdomains)
  • Opera 52.0: 43611 (+0 without subdomains)

A domain is in the “without subdomains” category if its include_subdomains property is set to true in transport_security_state_static.json, but the browser doesn’t preload its subdomains.

Note that we only count the domains that are in the current reference list. There are many domains that have been removed from the master list, but not yet removed from these browsers. So the actual number of preloaded domains in each browser should be slightly higher than the above result.

Edge:

Chrome:

Firefox:

Opera:

I think the reason why Firefox’s list is shorter than Chrome is that Mozilla regularly checks if domains still comply with the inclusion policy. Those which no longer send Strict-Transport-Security or the max-age is shorter than 18 weeks are automatically removed. Mozilla documents this policy at .

I find it quite surprising that Edge’s HSTS preload list is much shorter than other browsers. The does say that “like other browsers which have implemented this feature, the Microsoft Edge preload list is based on the Chromium HSTS preload list”. But Microsoft didn’t mention how often it’s updated or if Microsoft has extra requirements. Hopefully Microsoft will document their HSTS policies with more details in the future.

Conclusion
In this article, I have demonstrated how I use JavaScript and Fiddler to construct the HSTS preload list in Edge. In Part II, I will discuss how to find the exact preload list by reverse engineering.

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. #sharingiscaring

Xiaoyin Liu

Written by

info security enthusiast https://twitter.com/general_nfs

InfoSec Write-ups

A collection of write-ups from the best hackers in the world on topics ranging from bug bounties and CTFs to vulnhub machines, hardware challenges and real life encounters. In a nutshell, we are the largest InfoSec publication on Medium. #sharingiscaring