Hosting Autopsy / The HSTS setting that broke the intranet

The HSTS setting that broke the intranet

HOSTING AUTOPSY

6 min read · 1,258 words

This is a composite case written by the editors. It is built from patterns that come up often in support work and is not the account of a particular named person or company.

After a security review, an administrator enabled HSTS on the company's main domain with the option that includes all subdomains, and a long expiry. It was the textbook recommendation, and it came straight from the report: serve the site over HTTPS only, and tell browsers to remember that.

An internal tool lived on a subdomain that only supported plain HTTP. Browsers that had visited the main site now refused to load it over anything but HTTPS, and there was no way to click through the warning. Staff lost access to the tool until it was fixed.

Because the setting was cached in browsers for a year, the fix required putting a valid certificate on the internal tool rather than just removing the header. This is a composite of cases from a mid-sized services firm and a few others like it, and the sequence is the usual one: a sound change, a forgotten corner, and a setting that cannot be taken back quickly.

What HSTS does

HTTP Strict Transport Security is a header that a site sends over HTTPS. It tells the browser: for this host, and for a stated period, do not use plain HTTP at all. If someone types http:// or follows an old link, the browser rewrites the address to HTTPS itself, before any network request is made. It also changes how certificate errors behave. Without HSTS, a browser shows a warning for a bad certificate and lets the user click through. With HSTS, that option is removed.

A typical header looks like this:

Strict-Transport-Security: max-age=31536000; includeSubDomains

The number is the lifetime in seconds, here one year. The includeSubDomains directive extends the rule to every name beneath the domain: www.example.com, intranet.example.com, and any subdomain that anyone has created, forgotten or is yet to create. The browser stores this in its own database and applies it whether or not the site is reachable at that moment.

This is a useful protection. It stops downgrade attacks and cookie theft on shared networks. The administrator was right to want it. The mistake lay in the scope and in the speed, not in the idea.

Browser storesHSTS for example.comStaff openhttp://intranet.example.comRewritten tohttps:// inside browserTool listens onport 80 only: failsno click-through offered
The browser upgrades the address before sending anything, so the plain-HTTP tool never gets a chance to answer.

The change, and the first complaint

The security review had found that the main site sometimes loaded over HTTP and recommended HSTS with the usual long lifetime. The administrator added the header in the web server configuration for the main domain, tested the public site, saw the header in curl -I and closed the ticket.

The first complaint arrived the next morning from the finance team. The internal tool, an old reporting dashboard on intranet.example.com, would not open. The browser showed a connection error or a certificate error with no option to proceed. A colleague with a new laptop could open it without trouble. A contractor on a personal machine could too.

That pattern misled people. A tool that works for some and not for others suggests a permissions problem, a VPN issue or a faulty network switch, and the first two hours went on exactly those. The real difference was simple: the people affected had visited the main site since the change, so their browsers had stored the rule, and the others had not.

Why it could not be undone with a click

The administrator's first instinct was to remove the header. That was a reasonable move and it did nothing for anyone who already had it. A browser keeps the HSTS entry until its lifetime runs out, which here meant a year from the last time it saw the header. Removing the header stops new visitors from storing the rule and does not clear the stored one.

Two partial remedies exist. Sending the header again with max-age=0 over HTTPS tells browsers that see it to forget the entry, but only the browsers that come back to the main site and receive it. And on a single machine you can delete the entry by hand from the browser's internal HSTS page. For a company with a few hundred laptops, neither was attractive, and the manual route is awkward when the entry belongs to the parent domain with includeSubDomains, because the rule covering the subdomain is the parent's.

If a domain has ever been submitted to a browser preload list, the rule ships inside the browser itself, and removal takes months. Never submit a domain you have not fully audited.

There was also a political cost. The security team had asked for the change and the infrastructure team had made it, and the finance team, who could not run their month-end reports, did not much care whose idea it was. A rollback was proposed and rejected, because the main site now needed the header and the real defect was an HTTP-only tool that should never have been a dependency of anything important. The postmortem noted that the tool had been flagged in an earlier review and left alone because it still worked.

The fix: give the tool HTTPS

Since browsers would insist on HTTPS for the subdomain for up to a year, the quick way out was to make HTTPS work. The reporting dashboard ran on an old server that supported only port 80, so the administrator put a reverse proxy in front of it. The proxy held a valid certificate for intranet.example.com and passed requests to the tool over the internal network.

OptionTime to doComment
Reverse proxy with a public certificateAn afternoonWorks for every browser; certificate must be valid and renewed automatically
Certificate from an internal CAA day or moreEvery device must trust the CA; unmanaged devices will fail
Self-signed certificateMinutesDoes not work: HSTS removes the click-through
Wait for the lifetime to expireUp to a yearNot realistic

The self-signed route deserves a warning: it is the first thing people try, and under HSTS it fails exactly like no certificate. For names that are not reachable from the internet, a certificate can still be issued from a public authority using DNS validation, which proves control of the domain without exposing the server. Staff were back at work by mid-afternoon.

Lifetime in the browser, illustrativeAll at once1 yearStaged rollout5 min1 day1 week1 month, then 1 year when subdomains audited
A staged rollout means a mistake is forgotten within minutes or days, not a year.

How the rollout should have gone

Start with a short lifetime. Five minutes is enough for you to see the header working and for any broken page to recover quickly. Then raise it to a day, a week, a month, and only then to a year, leaving time between steps to collect complaints. Leave includeSubDomains off at first. Turn it on only after listing every subdomain, internal ones included, and confirming each serves HTTPS with a valid certificate.

The list is harder than it sounds. DNS zone files collect old names for printers, test boxes, vendor portals and tools that predate the person doing the review. Look in the zone, in the certificate transparency logs for public names, and ask teams what they run. Anything on the list that cannot do HTTPS needs fixing first or needs to move to a different domain.

What would have caught it

PreviousThe autoscaler that scaled to meet the botsNextThe IPv6 record pointing at nothing

More from Hosting Autopsy

Autopsy

The firewall rule that blocked the payment provider

After a burst of suspicious traffic, a developer added a rule that blocked all requests from addresses...

Autopsy

The CDN that served one customer's basket to another

A boutique put its site behind a CDN and turned on the option to cache everything, including HTML. Speed...

Autopsy

The scheduled job that ran twice

When an online business moved from one server to two, to be safe, it copied the whole server image. That...