OptStuff

Referer Security Model

Why the browser Referer header is reliable for anti-hotlinking, why it's not a substitute for authentication, and how OptStuff uses it alongside signed URLs.

When protecting image assets from unauthorized embedding, the HTTP Referer header is a surprisingly effective tool — if you understand its trust boundaries. This article explains when and why Referer is trustworthy, and how OptStuff leverages it as a supplementary anti-hotlinking layer.

What is the Referer header?

When a browser loads a resource (image, script, stylesheet, etc.), it typically includes a Referer header in the HTTP request that tells the server which page triggered the load.

GET /api/v1/my-blog/w_800,f_webp/cdn.example.com/photo.jpg HTTP/1.1
Host: optstuff.example.com
Referer: https://my-blog.com/posts/hello-world

The header is set automatically by the browser. JavaScript on the page cannot override it — this is a fundamental browser security guarantee.

Why is Referer trustworthy in browsers?

The browser enforces it — JavaScript cannot

The Fetch specification defines Referer as a forbidden header name. This means:

  • fetch() and XMLHttpRequest silently ignore any attempt to set it manually.
  • The browser always fills it in based on the actual page origin.
// This does NOT work — the browser ignores the custom Referer
fetch("https://optstuff.example.com/api/v1/...", {
  headers: { Referer: "https://evil.com" }, // silently dropped
});

A page on https://evil.com cannot forge a request that claims to come from https://my-blog.com. The browser guarantees the Referer reflects the real origin.

Browser extensions can — but that's fine

A browser extension or modified browser can alter the header. However, this requires explicit user action (installing an extension), which puts it in the same category as "the user can right-click → Save Image As." You're protecting against unauthorized websites, not against determined individual users.

The Fetch spec's referrer policy

Sites can restrict how much Referer information they send via the Referrer-Policy header. The available policies range from sending the full URL to sending nothing at all:

PolicyReferer sentExample
no-referrerNever(empty)
originOrigin onlyhttps://my-blog.com/
origin-when-cross-originOrigin for cross-originhttps://my-blog.com/
strict-origin-when-cross-origin (default)Origin for cross-origin, full for same-originhttps://my-blog.com/
unsafe-urlFull URL alwayshttps://my-blog.com/posts/hello-world

The default browser policy (strict-origin-when-cross-origin) sends the origin on cross-origin requests, which is exactly the information OptStuff needs for domain validation.

A site can choose no-referrer, which makes the header absent. But a site cannot make the header claim a different origin. This is the key distinction: a site can hide its identity, but it cannot impersonate another site.

When is Referer absent?

The Referer header is null in several legitimate scenarios:

ScenarioWhyExample
Server-to-server callsNo browser involvedSSR, cron jobs, webhooks
Referrer-Policy: no-referrerSite opted outPrivacy-focused sites
Direct navigationNo referring pageUser typed URL or used bookmark
HTTPS → HTTP downgradeBrowser strips it for security(rare in modern web)
Privacy toolsUser or extension strips itAd blockers, privacy extensions

These are all legitimate, non-malicious scenarios. Blocking them would create false positives without improving security — the signed URL already authenticates the request.

OptStuff's layered security model

OptStuff uses defense-in-depth with distinct layers, each protecting against a specific threat:

LayerPurposeProtects against
Signed URLs (HMAC-SHA256)Authentication — proves the request was authorized by someone with the secret keyUnauthorized access, URL forgery
Referer validationAnti-hotlinking — prevents authorized URLs from being embedded on unauthorized websitesBrowser-based hotlinking

Why this separation matters

Signed URLs are the real authentication. They cryptographically prove that someone with the secret key authorized this specific image request. This is the primary security gate.

Referer validation is supplementary. It solves a narrower problem: even with a valid signed URL, you may want to prevent it from being embedded on websites you don't control. Referer is the right tool for this because:

  1. It works against the actual threat (unauthorized websites embedding your images)
  2. The browser enforces it — the unauthorized site cannot bypass it
  3. It doesn't interfere with legitimate server-side usage

Absent Referer = allowed

When the Referer header is absent, OptStuff allows the request (assuming the signature is valid). This is the correct behavior because:

  • The signed URL already authenticates the request. If someone has a valid signed URL, they were authorized to use it.
  • Null Referer doesn't indicate hotlinking. It indicates a non-browser context (server-side rendering, API calls) or a privacy-stripping browser policy — none of which are the threat Referer validation targets.
  • Blocking null Referer creates false positives. It breaks SSR blur placeholders, cron-based pre-warming, health checks, and users with strict privacy settings — all without preventing any real attack.

An attacker who strips their own Referer to bypass the check could just as easily download the image with curl and self-host it. The Referer check isn't meant to stop that — it stops the much more common scenario of someone copy-pasting your <img> tag onto their website, where the browser will send the real Referer.

Summary

QuestionAnswer
Can a website forge the Referer header?No. Browsers forbid JS from overriding it.
Can a website hide the Referer header?Yes, via Referrer-Policy: no-referrer.
Should absent Referer be blocked?No. It indicates a non-browser or privacy-enhanced context, not hotlinking.
Is Referer a good authentication mechanism?No. Use signed URLs (HMAC) for authentication.
Is Referer a good anti-hotlinking mechanism?Yes. It reliably identifies which website triggered a browser request.

Last updated on

On this page