Compare commits
1 Commits
0598f1dc04
...
3127b4e5cc
| Author | SHA1 | Date | |
|---|---|---|---|
| 3127b4e5cc |
48
README.md
48
README.md
@@ -1034,20 +1034,40 @@ reduces the headers to a fixed allowlist — `Accept`, `Content-Length`,
|
||||
`Content-Type`, `Host`, `Origin`, `Referer`, `User-Agent` and
|
||||
`X-Request-Id`.
|
||||
|
||||
The body is replaced rather than filtered because the hook cannot tell
|
||||
which route it is on: the SDK hands `BeforeSend` no request, so a
|
||||
route-conditional rule would have to guess, and an unrecognised route
|
||||
must not leak. Nothing debuggable is lost by it. Every handler reads
|
||||
its fields with `PostFormValue`, so the body is exactly where the
|
||||
credentials are — the target destination URL, the login password, both
|
||||
password-change fields — and on the receiver route, the one route
|
||||
whose body is genuine signal, that body is already stored on the event
|
||||
and served from the UI. The headers are an allowlist for the same
|
||||
reason: the SDK's own filter removes four names and passes everything
|
||||
else, which would ship `X-CSRF-Token` and the shared secrets senders
|
||||
put on the receiver route. What survives still names the failing
|
||||
route — scheme, host, path, method — and `X-Request-Id` ties the event
|
||||
to the local access log line that holds the rest.
|
||||
The body is replaced on every route rather than filtered by route, and
|
||||
that is a choice rather than a limitation: the route is reachable from
|
||||
the hook. `sentryhttp`'s recover path puts the request on the context
|
||||
it hands to `RecoverWithContext`, and the SDK carries that context
|
||||
through to `BeforeSend` as `hint.Context`, so
|
||||
`hint.Context.Value(sentry.RequestContextKey)` yields the live request
|
||||
and chi's `RoutePattern()` yields the matched pattern off it. There
|
||||
are two reasons to redact unconditionally anyway. Nothing debuggable
|
||||
is lost:
|
||||
every handler reads its fields with `PostFormValue`, so the body is
|
||||
exactly where the credentials are — the target destination URL, the
|
||||
login password, both password-change fields — and the one route whose
|
||||
body is genuine signal is the receiver, whose body is already stored
|
||||
on the event and served from the UI, so a tracker is not where anyone
|
||||
reads it. And an unconditional rule cannot leak on a route somebody
|
||||
forgets to add to it, which a route-conditional one can.
|
||||
|
||||
The headers are an allowlist for that second reason: the SDK's own
|
||||
filter removes four names and passes everything else, which would ship
|
||||
`X-CSRF-Token` and the shared secrets senders put on the receiver
|
||||
route. What survives still names the failing route — scheme, host,
|
||||
path, method — and `X-Request-Id` ties the event to the local access
|
||||
log line that holds the rest. Nothing dropped is needed for the
|
||||
likeliest use, debugging a CSRF rejection. Its three inputs are the
|
||||
TLS decision, `Origin` and `Referer`; the latter two are kept, and the
|
||||
first is already in the retained URL, because the SDK derives that
|
||||
URL's scheme from `r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"` —
|
||||
byte for byte the predicate `internal/middleware/csrf.go` uses to
|
||||
choose between the `csrf.Secure(true)` and `csrf.Secure(false)`
|
||||
handlers. So dropping `X-Forwarded-Proto` costs nothing. The dropped
|
||||
provider headers (`X-GitHub-Event`, `X-Gitlab-Event` and the like) are
|
||||
real signal but are recorded locally on the event, and
|
||||
`Sentry-Trace`/`Baggage` are already reflected in the event's trace
|
||||
context.
|
||||
|
||||
The remaining client-supplied fields are truncated rather than dropped,
|
||||
each to a fixed budget: 512 bytes for `url`, `useragent` and `referer`,
|
||||
|
||||
Reference in New Issue
Block a user