Harden operator-set target headers (closes #233)
All checks were successful
check / check (push) Successful in 3m8s
All checks were successful
check / check (push) Successful in 3m8s
Three findings from the review of the per-target request headers feature. Configured headers no longer follow a redirect off the origin the target names. net/http withholds only Authorization and Cookie across a host change, so an operator's X-Api-Key or PRIVATE-TOKEN would follow a 302 to a host they never configured. Redirects are still followed — refusing them would break every destination that legitimately redirects and would record the 3xx as the delivery's result — but a hop to another host, another port, or down from https to http drops every header the target configured. The shared SSRF-safe transport is kept on that client, so each hop is still dialled through the private-IP guard. Trailer joins the reserved names. net/http strips it from the request it writes, so a configured one was accepted, stored, and provably never sent. The invalid-header-name error no longer quotes the text before the first colon. That text is only a name if it parses as one; when it does not, a pasted value whose own colon split the line put half a token into a 400 body. TestParseTargetHeaders_ErrorsNeverQuoteAValue asserted this invariant while only exercising the after-the-colon case, and now covers the before-the-colon one. README documents the http target's config keys, the 300-second timeout ceiling, the reserved-header list and the redirect behaviour; the edit form's hint gains Trailer and the redirect note.
This commit is contained in:
35
README.md
35
README.md
@@ -1049,6 +1049,41 @@ events should be forwarded.
|
||||
The `config` field stores type-specific configuration as JSON (e.g.,
|
||||
destination URL, custom headers, timeout settings).
|
||||
|
||||
**`http` target configuration:**
|
||||
|
||||
| Key | Type | Description |
|
||||
| --------- | ------------- | ----------- |
|
||||
| `url` | string | Destination the event is POSTed to |
|
||||
| `headers` | object | Extra request headers, applied last so they win over the event's own forwarded headers |
|
||||
| `timeout` | integer (sec) | Per-target request timeout; unset (or 0) uses the shared 30-second client timeout |
|
||||
|
||||
`timeout` is capped at **300 seconds**, and the form rejects anything
|
||||
above it rather than substituting the cap. A delivery attempt holds one
|
||||
of the bounded pool's workers for its whole duration, so an unbounded
|
||||
timeout would let a single unresponsive destination stall the queue.
|
||||
|
||||
`headers` rejects the names the delivery path or `net/http` writes
|
||||
regardless of what is configured: `Host`, `Content-Length`,
|
||||
`Transfer-Encoding`, `Connection`, `Trailer` and `User-Agent`. These are
|
||||
refused at the form rather than accepted and ignored, because a stored
|
||||
header that provably never reaches the wire tells the operator their
|
||||
configuration took effect when it did not. `Content-Type` is _not_
|
||||
reserved: a configured one deliberately overrides the event's.
|
||||
|
||||
**Redirects.** A redirect from an `http` target's destination is
|
||||
followed, up to ten hops, and the delivery's recorded status and body
|
||||
come from the final hop. Configured `headers` are dropped as soon as a
|
||||
hop leaves the origin the target names — a different host, a different
|
||||
port, or a step down from `https` to `http` — because a configured
|
||||
header is routinely a credential (`X-Api-Key`, `PRIVATE-TOKEN`) and an
|
||||
open redirect at the destination would otherwise hand it to a host the
|
||||
operator never chose. `net/http` already does this for `Authorization`
|
||||
and `Cookie`. Redirects within the target's own origin keep every
|
||||
configured header, so a destination that redirects its own paths is
|
||||
unaffected. Each hop is dialled through the same SSRF guard as the
|
||||
first, so a redirect aimed at a private or reserved address is refused
|
||||
at connect time.
|
||||
|
||||
#### APIKey
|
||||
|
||||
A programmatic access credential for API authentication.
|
||||
|
||||
Reference in New Issue
Block a user