Wymcp. Plugs. OriginCheck
(Wymcp v0.8.7)
View Source
The origin check (wire check):
DNS-rebinding protection for browser-based clients. It reads the Origin
header's cardinality, and rejects a request whose Origin is not on the
router's :origin allowlist when one is configured.
Protection against browsers, not support for them: wymcp serves no CORS
headers and no OPTIONS route, so a browser page reaches a mount only
through a CORS grant the host makes. README's Browser clients
section is the full statement.
A wire check on every non-fallthrough route; where it runs is
Wymcp.Router's wire-check invariant to state. It runs before anything has
validated Origin, which is exactly why this plug carries its own duplicate
arm instead of leaving cardinality to Wymcp.Plugs.SingletonHeaders.
Origin header | No allowlist (:origin omitted, or []) | Allowlist configured |
|---|---|---|
| absent | passes | passes — non-browser clients (curl, SDKs) send none |
| one value | passes | passes when on the allowlist, else 403 |
| two or more values | 400 | 400 |
The duplicate arm sits above the allowlist branch, so the two columns
agree on cardinality: a repeated header is the signature of a broken proxy,
and that does not depend on how the mount is configured. RFC 6454 forbids a
user agent from sending more than one Origin header field, and carries
several origins space-separated within one — so the values a single header
line holds are none of this arm's business, and a second line is a proxy
artefact.
The table's rows count what the adapter handed Plug, not what arrived
on the wire. Bandit preserves repeated header lines; Plug.Cowboy folds
them into one comma-joined value before this plug runs, so on Cowboy the
bottom row is unreachable and such a request takes the one value row
instead. README's Supported HTTP adapter section is the full statement
of what wymcp is tested against.
The 403's message quotes the refused Origin under the rule
Wymcp.Bound states in "What a refusal quotes", so a long one is cut and
marked …, and one that is not valid UTF-8 is quoted as its bytes rather
than failing to encode.
The rejection's envelope id is always nil, and structurally so — this
plug runs ahead of both the parse step and Wymcp.Plugs.Classify, so
Wymcp.Response.rejection_id/1 has no message kind to read even when the
body does carry an id. The nil is not a judgement about the message kind.