Correct trusted_proxies advice and state signature padding (closes #150)
check / check (push) Successful in 3m46s
check / check (push) Successful in 3m46s
The README told operators to set trusted_proxies to the proxy's own address. A proxy on the Docker host reaches pixa from the Docker network's gateway, so that advice made pixa count every user as one client for the login limit. The login-limit paragraph, the trusted_proxies entry and config.example.yml now say to use the address pixa sees for requests through the proxy, and how to read it from the request log. The signature section now says sig is base64url with the = padding kept, since pixa compares it exactly, and shows the example's sig for a stated key, computed with pixa's signer. Model: opus-5-5
This commit is contained in:
@@ -112,13 +112,18 @@ copy is fresh.
|
||||
The login form (`POST /`) is limited to 5 attempts per minute per client
|
||||
address, counting an IPv6 client by its /64; an attempt over the limit is
|
||||
refused with 429 and a `Retry-After` header. Behind a reverse proxy the client
|
||||
address comes from `X-Forwarded-For` only when the proxy's address is in
|
||||
`trusted_proxies`; otherwise all users behind the proxy are counted as one
|
||||
client. With the default `trusted_proxies` (the RFC 1918 ranges), a client
|
||||
with a private address can choose the address it is counted by through its own
|
||||
`X-Forwarded-For`, whether it connects directly or through the proxy, because
|
||||
its own address is trusted too. Setting `trusted_proxies` to the proxy's own
|
||||
address closes this.
|
||||
address comes from `X-Forwarded-For` only when the address pixa sees for
|
||||
requests that come through the proxy is in `trusted_proxies`; otherwise all
|
||||
users behind the proxy are counted as one client. That address is not always
|
||||
the proxy's own: for a proxy on the Docker host it is the gateway of the
|
||||
container's Docker network, such as `172.17.0.1` on the default bridge. pixa's
|
||||
request log shows it as `remoteIP` while it is not in `trusted_proxies` (see
|
||||
`trusted_proxies` under Configuration). With the default `trusted_proxies`
|
||||
(the RFC 1918 ranges), a client with a private address can choose the address
|
||||
it is counted by through its own `X-Forwarded-For`, whether it connects
|
||||
directly or through the proxy, because its own address is trusted too. Setting
|
||||
`trusted_proxies` to only the address pixa sees for requests that come through
|
||||
the proxy closes this.
|
||||
|
||||
### Image Metadata
|
||||
|
||||
@@ -172,19 +177,27 @@ Where:
|
||||
outside), or `cover` when the URL has no `fit`; a request whose `fit` is
|
||||
anything else, an empty `fit=` included, is refused with 400
|
||||
|
||||
**Example:** resize `https://cdn.example.com/photos/cat.jpg` to 800x600
|
||||
WebP with expiration 1704067200, default quality and fit:
|
||||
The URL's `sig` is the HMAC-SHA256 result in base64url (the URL-safe alphabet
|
||||
of RFC 4648) with the trailing `=` padding kept, 44 characters in all. pixa
|
||||
compares it exactly, so a signature encoded without padding, as Node's
|
||||
`base64url` and Go's `base64.RawURLEncoding` do, is refused with 401.
|
||||
|
||||
**Example:** with the signing key `example-signing-key-for-documentation`,
|
||||
resize `https://cdn.example.com/photos/cat.jpg` to 800x600 WebP with
|
||||
expiration 1704067200, default quality and fit:
|
||||
|
||||
1. Build input:
|
||||
`cdn.example.com:/photos/cat.jpg::800:600:webp:1704067200:85:cover`
|
||||
2. Compute HMAC-SHA256 with your secret key
|
||||
3. Base64URL-encode the result
|
||||
2. Compute HMAC-SHA256 of it with the signing key
|
||||
3. Base64URL-encode the result, keeping the `=` padding:
|
||||
`-ay7KHpfqmtIGbibDGbUuBDkymi-Ymdn0NkC6j5EJag=`
|
||||
4. URL:
|
||||
`/v1/image/cdn.example.com/photos/cat.jpg/800x600.webp?sig=<base64url>&exp=1704067200`
|
||||
`/v1/image/cdn.example.com/photos/cat.jpg/800x600.webp?sig=-ay7KHpfqmtIGbibDGbUuBDkymi-Ymdn0NkC6j5EJag=&exp=1704067200`
|
||||
|
||||
For the same image at quality 40 with fit `contain`, the input ends in
|
||||
`:40:contain` and the URL is
|
||||
`/v1/image/cdn.example.com/photos/cat.jpg/800x600.webp?sig=<base64url>&exp=1704067200&q=40&fit=contain`.
|
||||
`:40:contain`, the signature is `5IwXUx6vf7yefhaUvFzgXZvG2o0Df4RJxPTK3pKq5VU=`,
|
||||
and the URL is
|
||||
`/v1/image/cdn.example.com/photos/cat.jpg/800x600.webp?sig=5IwXUx6vf7yefhaUvFzgXZvG2o0Df4RJxPTK3pKq5VU=&exp=1704067200&q=40&fit=contain`.
|
||||
|
||||
**Allowlist patterns:**
|
||||
|
||||
@@ -246,8 +259,14 @@ Key settings in more detail:
|
||||
`172.16.0.0/12`, `192.168.0.0/16`), since pixa is deployed behind a
|
||||
proxy on a private network; an explicitly empty list (`[]`) trusts no
|
||||
one, and an explicit list replaces the default. An invalid CIDR aborts
|
||||
startup. Set this to your proxy's address range if it is not already
|
||||
covered by the defaults
|
||||
startup. Set this to the address pixa sees for requests that come through
|
||||
your proxy, such as `172.17.0.1/32`, when the defaults do not cover it, or
|
||||
to trust nothing else (see the login limit under Routes). For a proxy on
|
||||
the Docker host that address is the gateway of the container's Docker
|
||||
network (`172.17.0.1` on the default bridge), not the proxy's own address.
|
||||
To find it, set this to `[]` (or `PIXA_TRUSTED_PROXIES` to empty), send a
|
||||
request through the proxy, and read `remoteIP` in pixa's request log line
|
||||
for it
|
||||
- `upstream_fetch_timeout` — timeout for origin requests
|
||||
- `upstream_max_response_size` — max origin response size
|
||||
- `downstream_timeout` — client response timeout
|
||||
|
||||
Reference in New Issue
Block a user