skip to content

In a Strict-Transport-Security header, what is the max-age directive counting, and what does max-age=0 signal?

level: middleimportance: must knowfreq 62%

answer

  1. one required directive, one optional
  2. seconds, not a date
  3. clock starts at reception
  4. every visit slides it forward
  5. zero is the deletion signal

basics

~20 s

The Strict-Transport-Security max-age directive is a required delta-seconds value counting from the moment the browser received the header; it is how long that host stays a Known HSTS Host. max-age=0 tells the browser to drop the stored entry.

solid answer

~40 s

`max-age` is the one **REQUIRED** directive of the `Strict-Transport-Security` header field, and its value is a delta-seconds count. The clock starts when the browser **receives** the field, not when the response was produced, so every fresh visit that carries a valid field slides the expiry forward from that instant. Until it runs out, the host is a Known HSTS Host and the browser rewrites `http` URLs for it to `https` before making a request. Sending `max-age=0` over a secure connection is the deletion signal: the browser stops treating the host as known and drops the entry, and `includeSubDomains` has no effect when the value is zero. One more grammar rule matters in production — if more than one such field arrives on a single response, only the first is processed.

code

http · 3 lines
http
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=300
Content-Type: text/html; charset=utf-8

go deeper

for a junior

Know that the value is seconds and that it is compulsory — a Strict-Transport-Security field without max-age gives a browser nothing to store.

for a middle

Explain the reception anchor and the sliding window it creates, and say precisely what max-age=0 removes and what includeSubDomains does when the value is zero.

for a senior

Show that you have operated it: a long value is a commitment about every future secure connection to the name, and shortening it only reaches browsers that come back.

for a principal

Treat the number as a risk position across an estate, weighing the exposure a short value leaves against the outage surface a long one creates on names you do not operate.

## The grammar of the field `Strict-Transport-Security` carries a small, closed set of directives. RFC 6797 defines exactly two, and an interviewer expects you to know which is compulsory: | directive | status | value | what it sets | |---|---|---|---| | `max-age` | **REQUIRED** | delta-seconds | how long this host remains a Known HSTS Host | | `includeSubDomains` | **OPTIONAL** | none — it is valueless | whether names beneath this one are covered too | A field with no `max-age` is not a usable policy. A field with `includeSubDomains` alone says nothing about a lifetime, and there is no default lifetime to fall back on. ## What the count is counted from The value is **delta-seconds**: a plain count of seconds, not a date, not a timestamp, and not a lifetime anchored to anything on the host's side. It is measured from the moment the browser **received** the header field. That anchor has three consequences worth stating out loud: - **It has nothing to do with the response's age or freshness.** A `max-age` in a caching header and the `max-age` of `Strict-Transport-Security` are different directives in different header fields governing different things, and a candidate who conflates them will get the next question wrong too. - **It is not tied to the certificate.** Reissuing, rotating or renewing whatever the host presents does not touch a stored entry's expiry. - **It slides forward.** Every later visit that carries a valid field restarts the count from that reception. A site with steady traffic effectively keeps its regular visitors permanently covered with a modest value; a site visited once a year needs a value longer than a year to cover the same visitor's next trip. The practical shape of that last point: a value of `31536000` is 365 days, and `300` is five minutes. Both are legal. The choice is a commitment, because a browser that stops visiting keeps the entry for the full remaining count with no way for the host to reach it. ## What max-age=0 does `max-age=0` is the specified deletion signal. On receiving it over a secure connection, the browser stops regarding the host as a Known HSTS Host and removes the stored entry. Two details follow from that, and both come up: 1. **`includeSubDomains` is ignored when `max-age` is zero.** `max-age=0; includeSubDomains` does not somehow delete the parent while keeping the tree, and it does not delete only the subtree. The entry goes, and the directive has nothing left to qualify. 2. **It still has to arrive over a secure connection.** A deletion signal is a policy change, and a browser must ignore a `Strict-Transport-Security` field that arrives over non-secure transport — including one saying zero. You cannot clear a policy by turning TLS off and announcing the change in plaintext. ## Two rules that bite when more than one layer is involved - **Only the first field on a response is processed.** If a response somehow carries two `Strict-Transport-Security` fields — most often because something in front of the host adds its own alongside the application's — the browser processes the first and ignores the rest. A carefully tuned value further down the response has no effect at all, which is a quiet and very confusing failure. - **The field must not be sent over plaintext at all.** A host is required not to emit it there; a browser is required to ignore it there. ## Choosing a value Think of `max-age` as a promise about the future reachability of a name over TLS, not as a security dial to be turned to maximum. A long value on a name whose certificate operations are not reliable converts every future secure transport failure into an outage that a visitor cannot work around. A district portal whose certificate renewal is a scheduled, monitored job can carry a long value safely; a name maintained by nobody currently employed cannot. The usual, defensible progression is to start short, watch that nothing under the name breaks, then lengthen deliberately. Going the other way is much slower than it looks, because shortening only reaches a browser that comes back and makes a secure request while the shorter value is being served. ## Reading a field correctly Given `Strict-Transport-Security: max-age=86400; includeSubDomains` on a secure response, the correct reading is: from now, for 86,400 seconds — one day — treat this name and every name beneath it as a Known HSTS Host, rewriting `http` to `https` before any request is built; and refresh that one day from scratch on every later visit that repeats the field.

  • Does a browser that visits daily with max-age=86400 ever lose the policy?
    Not while it keeps visiting. Each valid field restarts the one-day count from the moment it is received, so the expiry is always a day away from the last visit. The entry lapses only after a full day with no secure request to the name — which is exactly what happens over a school holiday, and why a value should outlast the longest realistic gap between visits.
  • A response carries two Strict-Transport-Security fields with different max-age values. Which is stored?
    The first one on the response; the rest are ignored. Browsers do not merge the values, take the larger, or reject the response. This usually surfaces when a layer in front of the host adds its own field alongside the application's, and the value someone carefully configured is the one being discarded.
  • Can a host shorten an already-stored policy by sending a smaller max-age?
    Yes, but only to browsers that come back and make a secure request while the smaller value is being served. Each such visit replaces the stored expiry with the new count from reception. A browser that never returns keeps the old entry until the original count runs out, and nothing the host does can reach it.

saying these in an interview costs you the question

  • Reads max-age as a date or an absolute expiry time.
  • Confuses it with a cache freshness lifetime in another header field.
  • Thinks max-age=0 is rejected as invalid or means no expiry.
  • Believes includeSubDomains survives a max-age of zero.
  • Assumes a second field on the response can override the first.