HSTS Strict-Transport-Security for NZ sites: includeSubDomains, preload list and downgrade attack prevention

Quick answer

HSTS (HTTP Strict Transport Security) is one response header that tells every browser "for the next year, only ever load this site over HTTPS, even if a user types http:// or follows an insecure link." Once set, your site stops being reachable over plain HTTP for that period. The minimum header is Strict-Transport-Security: max-age=31536000; includeSubDomains. Adding preload lets you submit your domain to the browser-shipped HSTS preload list, so even the very first visit is protected.

If your site does not send HSTS today, the Free Website Security Check flags the missing header as a scanner hsts finding and tells you which snippet to paste.

What HSTS actually does

Every time a browser loads your site, your server has a chance to send back a short instruction in the response: "next time, and every time for the next N seconds, refuse to talk to me over plain HTTP." That instruction is the Strict-Transport-Security header, defined in RFC 6797.

Once a browser has seen the header, it will:

  • silently rewrite any http://yoursite.nz/... URL into https://yoursite.nz/... for the max-age period
  • refuse to connect to your site over plain HTTP for that period, even if the user typed http://
  • refuse to click through a "your connection is not secure" warning during that period

The header is what stops a class of attack where someone briefly forces a visitor over plain HTTP — for example on a coffee-shop Wi-Fi network — to capture session cookies or strip the HTTPS off a redirect (1). HSTS does not fix the redirect itself; it stops the visitor from ever landing on the unsafe version.

A typical NZ school or small-business site should ship this minimum header on every response:

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

That means: one year (31,536,000 seconds), and apply the rule to every subdomain (e.g. portal.yourschool.nz).

Why HSTS matters for New Zealand sites

HSTS is a one-line change with outsized impact. Three reasons it sits in the NZAI Security baseline:

  • The "first visit" problem. Without HSTS, the very first time a visitor reaches your site (typed URL, link from email, search result) is unprotected. A network attacker can briefly downgrade that visit to HTTP and capture whatever they need. HSTS closes the window on the second visit onward — and closes it on the very first visit if your domain is on the preload list.
  • CERT NZ names HTTPS-only as a baseline control. "Baseline controls" are the things CERT NZ expects every New Zealand organisation to have done before an incident is investigated (2). A scanner that flags hsts as missing is pointing at exactly that gap.
  • Privacy Act 2020 defensibility. Student data is in scope of the Privacy Act 2020 (3). If a misconfiguration leads to a breach, the Office of the Privacy Commissioner looks at what reasonable steps you took. Shipping HSTS is one of the cheapest reasonable steps available.

For the broader educator context (devices, accounts, phishing), see Building Cyber-Safe Habits as an NZ Educator.

The three directives: max-age, includeSubDomains, preload

The HSTS header has three things you can set. Each carries a tradeoff.

max-age

max-age=<seconds> is how long the browser should remember the rule. The IETF and the HSTS preload list submission page both require a minimum of 31536000 seconds (one year) for eligibility (1)(4). Shorter values are valid but give you less protection; longer values make the rule harder to undo if you ever need to roll it back.

A safe starter value is max-age=300 (five minutes) while you test — it gives you a quick exit if something breaks. Move to max-age=31536000 once you are confident.

includeSubDomains

includeSubDomains extends the rule to every subdomain. This is a powerful, irreversible-feeling statement: every *.yourschool.nz hostname is now HTTPS-or-nothing for the next year.

Only add includeSubDomains once every subdomain you own serves HTTPS. If you spin up a plain-HTTP staging.yourschool.nz after enabling it, every visitor's browser will refuse to load the new subdomain and silently rewrite the URL to HTTPS — which then fails because there is no TLS there (1).

For most NZ schools this means: turn it on, then sweep every DNS record and confirm every hostname has a valid cert.

preload

preload opts your domain into the browser-shipped HSTS preload list. Once accepted, the rule is baked into Chrome, Firefox, Safari, Edge and every browser that ships the list — so even a brand-new visitor on a brand-new device gets the protection on their very first visit (4).

Submission is permanent in spirit: removing a domain from the preload list takes months to propagate. Most NZ sites do not need preload to be safe; the basic max-age=31536000; includeSubDomains header is enough for almost every visitor.

HSTS Strict-Transport-Security for NZ sites — max-age, includeSubDomains, preload and HTTP-to-HTTPS redirect

The first-visit problem and how preload solves it

HSTS only fires after the browser has seen the header once. On the very first visit — typed URL, link from email, search click — the browser has no prior knowledge and will accept whatever your server offers. If an attacker is positioned on the network at that moment, they can downgrade that first visit.

preload closes the first-visit gap by baking your domain into the browser itself. Every browser that ships the list treats your domain as HSTS-enabled from the very first connection attempt, before any HTTP exchange has happened (4).

The tradeoff: submitting to the preload list is a one-way door. Once your domain is in the list, every subdomain must serve HTTPS, and getting out takes several browser release cycles. For most NZ sites, includeSubDomains without preload is the right balance.

Copy-paste fixes for the four common stacks

These snippets set the minimum recommended header. Paste them, restart the relevant service, and verify with the Free Website Security Check.

nginx

Add inside your server { ... } block:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Reload with nginx -s reload (or sudo systemctl reload nginx on systemd hosts). The always flag ensures the header is set even on error responses (4xx/5xx), which is what you want — it stops downgrade attacks on the error pages themselves.

Apache

Add inside your <VirtualHost>, or in an .htaccess in the document root:

<IfModule mod_headers.c>
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

If the header does not appear after reload, the most common cause is a mod_headers mismatch with how the site is hosted — confirm the module is loaded (apache2ctl -M | grep headers).

Express (Node.js)

Use the widely-trusted helmet package:

npm install helmet

Then in your app:

import helmet from 'helmet';
app.use(
  helmet({
    strictTransportSecurity: {
      maxAge: 31536000,
      includeSubDomains: true,
      preload: false,
    },
  })
);

Set preload: true only if you have submitted your domain to the preload list and every subdomain serves HTTPS (1).

Cloudflare

If you front your site with Cloudflare, you can enable HSTS from the dashboard:

  1. Go to SSL → Edge Certificates → HSTS → enable with max-age=31536000, includeSubDomains, and optionally preload
  2. Read the warning dialog carefully before submitting to the preload list — it is permanent
  3. Optionally set the same header at origin so it survives a Cloudflare bypass (e.g. direct API call)

Setting HSTS only at Cloudflare is enough for almost every visitor, but the moment Cloudflare is bypassed (direct origin traffic, an API call, a misconfigured DNS), your site loses the header. Set it at both layers where you can.

Common HSTS mistakes to avoid

From running the free scanner across New Zealand school and small-business sites, the most frequent missteps are:

  • Setting HSTS over plain HTTP. HSTS only works over HTTPS. If your site is still reachable over plain HTTP for any reason, the browser will not record the header from an HTTP response (1).
  • Adding includeSubDomains before checking every subdomain. A staging or dev subdomain on plain HTTP becomes unreachable to most visitors for the next year (1).
  • Setting max-age for a few days "to test". A short max-age does work for testing, but most production sites want the full year. Anything below 31536000 seconds makes you ineligible for the preload list (4).
  • Submitting to preload without includeSubDomains. The preload list requires includeSubDomains — submissions without it are rejected (4).
  • CDN stripping the header. If a CDN or reverse proxy sits in front of your origin, it can strip or rewrite the HSTS header. Verify through the CDN edge, not just from the origin server.
  • Forgetting always (nginx) / Header always (Apache). Without always, the header is only set on 2xx responses, leaving 4xx/5xx pages unprotected (4).
A reliable rule of thumb: any time a hsts finding reappears after you set the header, the problem is almost always a CDN or reverse proxy stripping it on the way out — not the origin config itself (1).

Verify before you ship

Setting the header is half the job. Two ways to confirm it is live:

1. Run the free NZAI scanner

The Free Website Security Check flags the missing HSTS header as a hsts finding and tells you which snippet to paste. Run it after every config change.

2. curl from the command line

curl -sI https://yoursite.nz | grep -i strict-transport-security

You should see the header name and your configured value. To bypass cache, append a fresh query string (?nocache=1) or test against a URL the cache has not seen.

Knowledge check

Test your understanding of HSTS with these questions. Click or tap each card to flip it and see the answer.

Q1You set HSTS with max-age=31536000 and includeSubDomains on Friday. On Monday morning the IT team spins up a new staging.yourschool.nz subdomain on plain HTTP for testing — and it stops responding entirely. What happened, and is it fixable without consequences?tap to flip
Answer: This is exactly what HSTS was designed to do. Every visitor who has visited any subdomain of your school in the last year has been told that all subdomains must use HTTPS for the next year. Their browser now refuses plain HTTP on staging.yourschool.nz and silently rewrites it to HTTPS. If the subdomain does not serve HTTPS, the user's browser shows an error. Fixing it requires serving HTTPS on the subdomain — there is no way to "undo" HSTS for affected visitors during the max-age period, which is why includeSubDomains should only be added once every subdomain is HTTPS-ready (1).
Q2You submit your domain to the HSTS preload list on Monday. On Wednesday, the Ministry of Education spins up a new learn.yourschool.nz subdomain for a temporary pilot project that does not have HTTPS ready. What happens?tap to flip
Answer: The new subdomain is broken from day one. Every browser that ships the preload list will refuse plain HTTP on learn.yourschool.nz and silently rewrite to HTTPS, which then fails because there is no TLS there. The preload list also requires includeSubDomains, so the same rule covers every existing subdomain too. The only fix is to set up HTTPS on the new subdomain before launching it — and that is exactly the kind of operational pressure the preload list is designed to apply. Removing a domain from the preload list takes months of browser release cycles (4).
Q3Your site sends HSTS but a CDN in front of your origin strips it on some responses. Visitors still see HTTPS in their browser. Is this a problem?tap to flip
Answer: It can be. The browser only records the HSTS rule from responses that actually carry the header. If your CDN is inconsistent (some responses have the header, some do not), some browsers will record the rule and some will not — leading to inconsistent behaviour and downgrade windows. Always verify the header end-to-end through the CDN edge (curl -sI https://yoursite.nz), not just from the origin server (1).

Sources and references

[1] Internet Engineering Task Force. (2012). RFC 6797 — HTTP Strict Transport Security (HSTS). https://datatracker.ietf.org/doc/html/rfc6797

[2] CERT NZ. (2025). Top 11 cyber security tips for your business. https://www.cert.govt.nz/business/guides/top-tips-for-cyber-security/

[3] New Zealand. Parliament. (2020). Privacy Act 2020. https://www.legislation.govt.nz/act/public/2020/0031/latest/whole.html

[4] Chromium Project. (2025). HSTS preload list submission. https://hstspreload.org

[5] Mozilla. (2025). MDN Web Docs — Strict-Transport-Security header. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security

What to do next