Fathom sends its pageview as an image request. script-src named the origin and img-src did not, so the script loaded and the one thing it loads to do was blocked — visible only in the browser console, with a 200 on every response and no pageview at the other end. The console said it plainly: Loading the image 'https://cdn.usefathom.com/?h=...&sid=ZPKDEHCV...' violates the following Content-Security-Policy directive: img-src 'self' A test now asserts the origin appears under all three directives it actually uses, because nothing on this side of the wire can tell that it does not.
62 lines
3.4 KiB
Plaintext
62 lines
3.4 KiB
Plaintext
# Response headers for bench.12vectors.com.
|
|
#
|
|
# Read by Cloudflare Workers static assets at deploy time — the file is
|
|
# consumed, never served — and copied here from site/root/ by
|
|
# site/build.py, because the host looks for it at the root of the build
|
|
# and nowhere else.
|
|
#
|
|
# Rules do NOT override each other: a header two matching rules both set
|
|
# arrives concatenated. Measured on the live site, not assumed —
|
|
# /* and /static/* both setting Cache-Control produced
|
|
#
|
|
# cache-control: public, max-age=0, must-revalidate, public,
|
|
# max-age=31536000, immutable
|
|
#
|
|
# on the stylesheet, and the first max-age wins in every browser, so the
|
|
# year-long cache never happened. So exactly one rule may set a given
|
|
# header: Cache-Control is set on /static/* alone, and HTML is left to
|
|
# the host's own default, which is the revalidating one. Check #4 after a
|
|
# deploy is what keeps that honest.
|
|
|
|
# Everything, so that no page can ever forget one of these.
|
|
#
|
|
# nosniff a text/plain file must not become a script
|
|
# Referrer-Policy a full url is never sent to another origin
|
|
# HSTS one year, this host and anything below it. No
|
|
# `preload`: that is a submission to browser
|
|
# vendors and a commitment this card did not make
|
|
# X-Frame-Options nothing here is meant to be framed
|
|
# CSP the runtime form of the site's own promise.
|
|
# `default-src 'none'` means an asset must be
|
|
# named below to load at all, and no
|
|
# 'unsafe-inline' anywhere means an injected
|
|
# <script> does not run. One origin besides
|
|
# 'self' is named: cdn.usefathom.com, which
|
|
# serves the analytics script and receives its
|
|
# pageviews. It appears in THREE directives, and
|
|
# img-src is the one that is easy to miss:
|
|
# Fathom sends its pageview as an image request,
|
|
# so script-src alone loads the script and blocks
|
|
# everything it was loaded to do — silently, on
|
|
# the browser's side, where no deploy check
|
|
# looks. Fathom sets no cookie and collects
|
|
# nothing about a person, which is why it needs
|
|
# no banner — but it is a third party, and the
|
|
# policy says so out loud rather than quietly
|
|
# allowing everything
|
|
/*
|
|
X-Content-Type-Options: nosniff
|
|
Referrer-Policy: strict-origin-when-cross-origin
|
|
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
|
X-Frame-Options: DENY
|
|
Content-Security-Policy: default-src 'none'; style-src 'self'; font-src 'self'; img-src 'self' https://cdn.usefathom.com; script-src https://cdn.usefathom.com; connect-src https://cdn.usefathom.com; base-uri 'none'; form-action 'none'; frame-ancestors 'none'
|
|
|
|
# The stylesheet and the icon are linked with a ?v=<hash> of their own
|
|
# contents (site/build.py, stamp()), and the fonts never change under a
|
|
# given filename. All of it is safe to keep for a year and never check:
|
|
# a deploy that changes the stylesheet changes the url that asks for it.
|
|
# The only rule in this file that sets Cache-Control, for the reason at
|
|
# the top — a second one would concatenate rather than lose.
|
|
/static/*
|
|
Cache-Control: public, max-age=31536000, immutable
|