A SAML identity provider is asked to post an assertion to an AssertionConsumerServiceURL it has never registered — what should it do, and why?
answer
- the duty is on the issuing side
- a request nominates, it does not instruct
- match against what that party registered
- whole-value match, never a prefix
- an index references a registered endpoint instead
basics
~20 sIt should refuse to deliver there. The Web Browser SSO profile obliges the asserting party to establish that the delivery location really is controlled by the service provider it is asserting about, and honouring an unregistered location hands a valid signed assertion to whoever nominated it.
solid answer
~40 sReject the delivery and return an error rather than issue to that location — typically a `<StatusCode>` of `urn:oasis:names:tc:SAML:2.0:status:Requester`. The obligation sits on the **issuing** side: before posting, the identity provider must have some means of establishing that the location belongs to the party named in the message, and the ordinary means is matching the requested `AssertionConsumerServiceURL` against the endpoints registered for that `entityID`. If it skips the check, anyone who can put a request in front of it can have a genuine, correctly signed assertion about an already-signed-in person delivered to a location they control. The signature does not save you: it makes the document credible, which is precisely what makes misdelivery valuable. Referring to a registered endpoint by `AssertionConsumerServiceIndex` avoids the problem, because then no location travels in the message at all.
code
pseudocode · 16 lineson sign-on message from party P:
registered = endpoints registered for P.entityID
if message has AssertionConsumerServiceIndex:
location = registered[index] # no sender-chosen value
else if message has AssertionConsumerServiceURL:
if message.AssertionConsumerServiceURL not in registered:
respond with StatusCode urn:oasis:names:tc:SAML:2.0:status:Requester
do not issue an assertion
return
location = message.AssertionConsumerServiceURL
else:
location = registered.default
authenticate the person
issue signed assertion for P and post it to locationgo deeper
Take away the rule: the party issuing a statement decides where it is delivered, and it only delivers to locations it already knows belong to the party it is asserting to.
Explain the mechanism both ways — what the issuing side matches the requested location against, and what an attacker gets if that match never happens.
Walk the attack as a sequence, state its bound honestly, and name the two implementation errors that recreate it: prefix matching, and trusting a value because the connection looked normal.
Treat the registered-endpoint list as a controlled asset across the whole counterparty estate: who may add one, how control of the host is demonstrated, and how stale test endpoints get pruned.
## Where the obligation sits SAML's Web Browser SSO profile puts a duty on the party that **issues**, not only on the party that consumes. Before an identity provider posts an assertion to an assertion consumer service location, it must have some means of establishing that the location is in fact controlled by the service provider it is asserting to. That is a statement about delivery, and it is easy to lose because everything else in the protocol pushes attention toward the consuming side's validation. A sign-on message may nominate where the answer should go, as an `AssertionConsumerServiceURL`. Treating that value as an instruction rather than a request is the inversion this leaf exists to name. ## The failure when the check is skipped The sequence is short and it works: 1. an attacker composes a sign-on message naming a real service provider's `entityID` but an `AssertionConsumerServiceURL` pointing at a host the attacker runs; 2. a person who already has a session at the identity provider follows the link, so no credential prompt appears and nothing looks unusual; 3. the identity provider authenticates the person from its existing session, issues a correctly signed assertion naming that person, and posts it to the nominated location; 4. the attacker now holds a valid, signed, current assertion about that person. What the attacker gains is bounded but real: the assertion names the service provider it was meant for, so it is not a universal credential — but it is a working credential *at that service provider*, and replaying it to the real assertion consumer service is the obvious next step. The bound is a reason to state the limit accurately, not a reason to relax. ## Why signing does not fix it Two reflexes are worth killing here. - **"The assertion is signed, so it cannot be abused."** The signature makes the document credible. Credibility is exactly what makes a misdelivered assertion worth stealing; an unsigned one would be worthless to the attacker. - **"The connection came from the right place."** A sign-on message arrives through a browser. There is no channel-level fact about it that says anything about who composed it, and TLS to the identity provider authenticates the identity provider to the browser, in the other direction entirely. ## What the check actually is | Option | What travels in the message | What the issuer must do | |---|---|---| | `AssertionConsumerServiceURL` | a location, chosen by the sender | match it against the endpoints registered for that `entityID`, and refuse if absent | | `AssertionConsumerServiceIndex` | a reference to one of the party's registered endpoints | resolve the index against the registration; no attacker-chosen location exists | | neither is present | nothing | deliver to the party's default registered endpoint | The comparison against the registered set is a **whole-value** match, not a prefix or substring test. Prefix matching is how this defence is usually defeated in practice: a registered `https://sp.example.net/saml/` will happily prefix-match `https://sp.example.net/saml/../[email protected]` shaped values, and the check becomes decoration. When the requested location is not registered, the conforming behaviour is to not deliver an assertion at all. Returning an error to the requester — a `<StatusCode>` of `urn:oasis:names:tc:SAML:2.0:status:Requester` — is the usual way to say so, and it is a far better outcome than a silent success at the wrong host. ## Who checks what, on each side - **Issuing party:** that the delivery location belongs to the party named in the message; that it will only sign statements for parties it has registered. - **Consuming party:** that the assertion it received was issued by the key it trusts, is addressed to it, and is still within its validity window — and that it arrived at the endpoint it expects to receive it on. Neither list substitutes for the other. A deployment where the issuing side skips its half is a deployment where the consuming side's careful validation is bypassed entirely, because the attacker simply becomes the consumer's caller with a genuine document in hand. ## Operating it in a real estate In a port community with dozens of counterparties, the registered-endpoint list is the whole defence, so it needs to be operated as such: - registration is a change with an owner, not a self-service field on a form; - every added or edited endpoint is an `https` location on a host the counterparty demonstrably controls; - endpoints that were added "temporarily for testing" outlive the test and should be pruned on a schedule; - prefer index-based references where the counterparty's software supports them, since the safest value to validate is one that never travelled.
- The sign-on message was signed by the service provider's own key. Does that settle the delivery location?It establishes that the party asked, which is a stronger position, but the obligation is still to deliver to a location established as that party's. A signed message with an unregistered location usually means a misconfigured counterparty rather than an attack — and answering with an error surfaces that, whereas delivering hides it until something worse happens.
- What does the attacker actually gain if the check is skipped?A genuine, signed, current assertion about a person who was already signed in, addressed to one particular service provider. It is not a universal credential, but it can be replayed at that service provider to obtain that person's session there. Bounded blast radius is not the same as harmless.
- Why is matching the requested location against a registered prefix not good enough?Because a prefix test accepts values the registration never sanctioned — anything the attacker can append or smuggle past the matched portion. The comparison must be against whole registered values, which is also why referring to an endpoint by index is safer: nothing arbitrary travels in the message to compare.
saying these in an interview costs you the question
- Says a signed assertion cannot be misused, so delivery location does not matter.
- Treats the delivery location in the message as an instruction to obey.
- Claims TLS on the inbound connection establishes who composed the message.
- Prefix-matches the requested location against a registered one.
- Puts the whole obligation on the consuming side's validation.
- Assumes an unregistered location is harmless because the person still authenticated.