skip to content

A Content-Security-Policy ships both block-all-mixed-content and upgrade-insecure-requests - which is obsolete, and why is the other not?

level: middleimportance: nice to knowfreq 26%

answer

  1. one blocks, one rewrites
  2. the default moved under one of them
  3. the loophole it closed is already closed
  4. blockable content was never its contribution
  5. rewriting still reaches what upgrading misses

basics

~20 s

block-all-mixed-content is obsolete: everything it used to catch is now either upgraded automatically or already failed. upgrade-insecure-requests is not, because it rewrites the blockable requests - scripts, stylesheets, data requests - that no automatic upgrade will touch.

solid answer

~50 s

`block-all-mixed-content` existed for one reason: to switch off the exemption that let plaintext images, audio and video load on an HTTPS page with only a warning. That exemption is gone - browsers now autoupgrade those requests instead - and everything outside that narrow set was already failed as a network error. With nothing left for it to catch, the specification marks the directive **obsolete**. The only residual difference is the outcome for an upgradeable request: the old directive would fail it, while the current default retries it over `https`, which is strictly better. `upgrade-insecure-requests` survives for the opposite reason - it is not a blocking directive at all. It rewrites insecure requests to `https` *before* the mixed-content check, and it covers the blockable requests autoupgrade leaves alone. Keep it if plaintext addresses are still in your content; drop the obsolete one.

code

http · 8 lines
http
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

# what an older deployment guide recommended
Content-Security-Policy: block-all-mixed-content; upgrade-insecure-requests

# what is worth shipping now
Content-Security-Policy: upgrade-insecure-requests

go deeper

for a junior

Recall that only one of the two is worth shipping today: the upgrading directive. The blocking one is marked obsolete in the specification.

for a middle

Explain the asymmetry: blocking became the default for everything outside the narrow upgradeable set, while upgrading never became the default for blockable requests, so only the rewriting directive still changes an outcome.

for a senior

Name the residual difference honestly - the obsolete directive would fail an upgradeable request that the current default upgrades - and audit a copied policy for directives that no longer buy anything.

for a principal

Treat a policy that accumulates retired directives as the symptom: without an owner and a review date, a security header becomes a checklist artefact nobody can explain or safely remove.

## Two directives that sound like a pair and are not They arrived together and read like a toggle - one blocks, one upgrades - but they act at different points and only one is still doing work. - **`block-all-mixed-content`** was a *strengthening* directive. Its job was to remove the exemption that let the narrow upgradeable set load in plaintext with nothing but a console warning, so that **every** insecure subresource failed. - **`upgrade-insecure-requests`** is a *rewriting* directive. It never blocks anything; it changes insecure URLs to `https` before the mixed-content check runs. ## Why the blocking one has nothing left to do Walk the two categories under current browser behaviour: 1. **Blockable mixed content** - scripts, stylesheets, frames, data requests, `ws` connections - is failed as a network error with no directive at all. The directive added nothing here, ever. 2. **Upgradeable mixed content** - an image request with an empty initiator, audio, video - is no longer loaded in plaintext. It is rewritten to `https` and fetched. The warning-only loophole the directive was written to close **no longer exists**, so there is no request left that the directive changes the fate of in the direction it was meant to. That is why it is marked obsolete. Be precise about the one residual difference, because it is the honest edge of the claim: the outcomes are not literally identical. Under the old directive an upgradeable plaintext image was **failed**. Today it is **upgraded and usually loads**. Shipping the obsolete directive on a browser that still honours it therefore does not make the page safer - it makes plates disappear that would otherwise have rendered over `https`. | | `block-all-mixed-content` | `upgrade-insecure-requests` | |---|---|---| | What it does | fails insecure requests | rewrites insecure requests to `https` | | When it acts | at the mixed-content check | **before** it | | Reaches blockable content | already failed anyway | **yes - this is the point** | | Reaches upgradeable content | failed it | upgrades it | | Status | **obsolete** | current | ## Why the rewriting one survives Autoupgrade is generous with images, audio and video and does nothing for anything else. If a catalogue record hands the viewer `http://assets.example.org/viewer.js`, autoupgrade will not touch it and the script is simply gone. `upgrade-insecure-requests` rewrites it, and because the rewrite happens first, the mixed-content check afterwards has nothing to act on. So the two directives are not a strong-and-weak pair. One tried to widen *blocking* in a world where blocking is already the default, and the other widens *rewriting*, which is the only part still worth having. ## What to do with a policy that carries both - **Remove `block-all-mixed-content`.** It buys nothing, and where it is still honoured it turns an upgrade into a failure. - **Keep `upgrade-insecure-requests` while plaintext addresses are still in the content**, and treat it as a bridge rather than a fix - it rewrites for browsers only, so an export job or a feed reading the same records still emits plaintext addresses. - **Do not read either one as a substitute for the content change.** A record that stores an absolute plaintext address is the defect; a document policy is the sandbag around it. ## The sentence to be able to say "Blocking became the default, so the blocking directive is obsolete; upgrading never became the default for blockable requests, so the upgrading directive is not." That single asymmetry is the whole answer, and it is why the two directives, which are usually named in the same breath, have opposite fates.

  • If a browser still honours block-all-mixed-content, does shipping it make the archive viewer safer?
    No - it makes it emptier. The requests it would fail are the upgradeable ones, which the current default retries over `https` and usually loads successfully. Everything else was already failed without any directive. So the directive's only reachable effect today is to turn plates and recordings that would have rendered securely into missing ones.
  • Could you keep upgrade-insecure-requests permanently instead of fixing the stored addresses?
    It would keep browsers working, but it is a browser-side document policy, so anything else reading those records - an export, a feed, a partner integration - still receives plaintext addresses and gets no rewrite. It also silently depends on every referenced host continuing to serve the same paths over `https`. Treat it as a bridge with an end date.

saying these in an interview costs you the question

  • Treats the two directives as a block-or-upgrade toggle
  • Says block-all-mixed-content is still the strict option to ship
  • Thinks upgrade-insecure-requests is obsolete along with it
  • Claims the obsolete directive was what blocked plaintext scripts
  • Assumes both directives act at the same point in the request path