skip to content

What makes a mix-up attack possible against a client that accepts logins from three partner authorization servers?

level: middleimportance: should knowfreq 45%

answer

  1. needs more than one provider
  2. the callback does not say who answered
  3. a response fitted to the wrong flow
  4. code posted to the wrong token endpoint
  5. the client's own credential goes with it

basics

~20 s

A mix-up attack needs a client able to start flows at more than one authorization server. Nothing in a plain OAuth 2.0 authorization response names the server that produced it, so one server's response can be processed as another's.

solid answer

~40 s

The precondition is plurality: the client can begin an authorization flow at any of several servers, and its callback is a single endpoint that receives `code` and `state` with no indication of who sent them. The attacker's goal is to have a response that was produced at one authorization server processed as though it belonged to a flow the client started at another. The client then continues the flow against the wrong party - it posts the `code` to that party's `token_endpoint`, together with whatever it authenticates with there. The attacker gets an authorization code issued by an honest server, and often the client's own token-endpoint credential as well. Exact `redirect_uri` matching does not help, because it fixes where a response is delivered, not who produced it.

code

http · 5 lines
http
GET /callback?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj HTTP/1.1
Host: timetable.example

# Three partner authorization servers could have produced this.
# Nothing in the request distinguishes them.

go deeper

for a junior

Hold on to the shape: one callback, several possible providers, and a response that does not say which one sent it. The attack is about attribution, not about a broken signature or a stolen key.

for a middle

Explain the precondition and the consequence as a sequence - which flow the client thinks it is in, which token endpoint it then posts to, and what leaves the client with that post.

for a senior

Be ready to say precisely why state and exact redirect_uri matching leave this open, and to describe the bookkeeping a client must keep per flow rather than naming a parameter and stopping.

for a principal

Treat adding a second identity provider as the point where response attribution becomes a standing requirement across every client in the estate, including ones nobody expected to become multi-provider.

## The precondition is plurality A mix-up attack is not available against a client wired to a single authorization server. It becomes available the moment the client can start a flow at more than one - the case of an application that offers sign-in through several partner institutions, each running its own **authorization server** with its own `issuer` identifier, `authorization_endpoint` and `token_endpoint`. The client's callback is normally one endpoint for all of them. What arrives there is an authorization response: a `code`, the `state` the client sent out, and nothing that names the server that produced them. The client must therefore reach into its own bookkeeping and decide which flow this response belongs to. **That decision is the thing under attack.** ## How the confusion is produced The front channel runs through the user's browser, which makes it visible and manipulable in a way the back channel is not. Several routes lead to the same end state: - The attacker influences the **choice of provider** at the point where the user picks one, so the client's record of the flow names one authorization server while the user is actually sent to another. - The attacker starts a flow of their own at an honest authorization server and gets the resulting response delivered into the victim client's callback, where it is matched to an unrelated flow in progress. - Any step that lets the attacker interpose on the front-channel leg - a page the user is walked through, a redirect the client performs on its own site - can make the client's stored notion of the current flow disagree with the flow that actually ran. The common factor is never a broken signature or a decrypted secret. It is a **bookkeeping mismatch** that every individual message is entitled to produce, because no individual message carries the fact that would settle it. ## What the client then does Having decided, wrongly, which flow the response belongs to, the client continues with the grant. It sends the `code` to the `token_endpoint` of the authorization server it *believes* it used, and it authenticates itself there in whatever way that server expects. Two things are now in the wrong hands. | What moves | Where it goes | Why it matters | |---|---|---| | The authorization `code` | The token endpoint of the wrong authorization server | An honest server's code is handed to a party that was never part of that grant | | Whatever the client presents to authenticate at the token endpoint | The same wrong party | The credential the client uses with a legitimate server is disclosed to another | | The client's decision about who the user is | Stays inside the client | It was reached from a response the client cannot attribute | ## Why the parameters already present do not settle it - **`state`** binds a response to the authorization request the client started and to the browser session it started from. That is a real property, and it is not this one: an attacker able to arrange the confusion can arrange for the correct `state` to come back. `state` says *this answers my request*, never *this came from that server*. - **Exact `redirect_uri` matching** fixes the destination of a response. It is enforced by the authorization server against its own client record, and it has nothing to say about which server a client later receives a response from. - **TLS on the callback** protects the response in transit between two endpoints. It does not tell the receiving endpoint which of three possible peers produced the content. ## What actually closes it The defence is to make the response say who answered, and to check it against who was asked. Concretely, either the authorization response carries the issuer identifier of the server that produced it - the parameter RFC 9207 defines for exactly this - or the client arranges its own endpoints so the callback path itself identifies the authorization server, by giving each one a distinct redirection endpoint. RFC 9700 treats a mix-up defence as required and names the issuer parameter as the mechanism to use. The practical shape of the fix inside a client is the same either way: for every flow it starts, record which authorization server it was started at, and refuse to continue a flow against a different one.

  • In the worst case, what does the client hand to the wrong party?
    The authorization `code` issued by an honest server, plus whatever the client presents to authenticate at the token endpoint it posts to. The attacker receives a code they were never granted and a credential the client uses with a legitimate authorization server, in one request.
  • A client talks to exactly one authorization server today. Is it exposed to mix-up?
    Not while that holds - the precondition is the ability to start a flow at more than one server. The exposure appears with the second provider, which is why the defence is added when the second integration is, not after an incident.
  • Does it matter whether the attacker's own authorization server is one the client trusts?
    It sharpens the attack but is not required. A client willing to start flows at an attacker-operated server can be made to carry an honest server's code there; a client trusting only reputable servers can still be made to confuse two of them with each other.

Two unmarked envelopes arrive in the same post, with nothing on either to say which correspondent sent it. Open them against the wrong orders and the reply you post back, enclosures and all, goes to the party who should never have received it.

saying these in an interview costs you the question

  • Says the state parameter prevents mix-up attacks
  • Thinks a single authorization server is enough for the attack
  • Assumes TLS on the callback rules it out
  • Calls it a redirect URI validation failure at the client
  • Believes exact redirect_uri matching identifies who answered