A signed URL proves that your application generated it, so the server
rejects any URL a client edited or made up. A concealed source goes further
and hides which image the URL points at. Both are optional, and both work the
same for image_pipe_server and ImagePipe.Plug.
- Signing URLs and rotating keys: turning on signing and replacing a key.
- Shared URL settings: the keys and other settings the server and the URL builder must agree on.
- Signed URLs: what a signed URL looks like to the people who request images.
Purpose of signing
Without signing, anyone who can reach the server can request any size, crop,
or effect of any image the server can read. Each new combination is a new
image to fetch, process, and store in the cache. With signing keys
configured, the server serves only the URLs your application generated, and
answers every other request with 403 before it fetches the source or reads
the cache.
What a signature covers
https://img.example.com/images/sig=<signature>/w=400/expires=1767225600/src/photos/beach.jpgThe signature is an HMAC-SHA256 of everything after the sig= segment: the
options, the expiry, and the image path, byte for byte. Changing any of them
gives 403 with the body invalid signature.
The hostname and the path the server is mounted at (/images here) are
outside the signature. A URL signed for your CDN's address is also valid at
the server's internal address, and moving the server to another path needs
no new signatures.
The signature covers a preset's name, not its definition. When the server's
card preset changes from 400 to 480 pixels wide, every signed
preset=card URL stays valid and serves the wider image.
Expiry
A signed URL can carry an expires time, in Unix seconds. The server accepts
the URL up to and including that second and answers 410 with the body
expired after it, before fetching the source. The expiry is inside the
signed part of the URL, so a client can't extend it. Without signing keys,
the server still checks expires, but anyone can edit it.
An expiry is part of the URL, so a URL generated with a new expiry on every page view is a new URL every time, and browsers and CDNs can't reuse their cached copy.
Signing keys
A signing key is a secret, written as hex. The server and the URL builder each hold a list of keys. The builder signs with the first key in its list, and the server accepts a signature made with any key in its list.
The list is what makes it possible to replace a key without breaking URLs already in use: the server accepts the old and the new key while URLs signed with either are still requested. Signing URLs and rotating keys gives the steps.
Anyone holding a key can sign any URL, which is why URLs are generated in server code and the browser receives only the finished URL.
Source concealment
A concealed source replaces src/photos/beach.jpg with an encrypted token:
/images/sig=XzyslPgT…/w=400/enc/Aa_ELvrY…The token hides the whole source, including a private hostname, the path, and credentials in its query string. Watermark sources in the same URL are encrypted too. The token is encrypted with source encryption keys, which are separate from the signing keys, and concealed URLs are always signed. Shared URL settings shows how to configure the keys on both sides.
Deterministic and random tokens
By default, the same source and encryption key always give the same token,
whatever the processing options, and in any process. A URL for beach.jpg at
w=400 and one at w=400/-/blur=2 carry the same enc/ token.
Generating the same URL again gives the same string, so browsers and CDNs
keep reusing their cached copy.
In random mode (the URL builder's iv_mode option, see
source encryption keys),
each URL gets a new token. Random tokens hide that two URLs show the same
image, at the cost of a new URL each time for browsers and CDNs. The server
caches the processed image by its decrypted source, so both modes share the
server's stored copies and ETags with each other and with the same source
written as src/.
What a token reveals
- A token's length shows the source's length to within 16 bytes.
- Deterministic tokens show which URLs have the same source.
The token protects the source only while nobody else can encrypt with your keys, so no endpoint may encrypt any source it's given. With such an endpoint, someone can encrypt a guessed source and compare the token with a URL they've seen.