Core - 15.5.3 CSRF Attack on Fragment Response Example

Issue #1752 open
adam strickland created an issue

This section outlines how a JavaScript Client could proxy the authorization response down to a Web Server Client for validation, but the example /catch_response endpoint it shows is vulnerable to a CSRF attack.

The format of the request sent to this endpoint is a simple request, and will not trigger a CORS preflight. Any malicious website could POST to it in a CSRF attack (baring other validation done on the server).

Given that the state parameter is used for CSRF protection, we should edit the example to be in a format that would be CSRF protected by default. Specifically, the state parameter should be moved to a customer request header, like in this example.

It would be best to add guidance on the following 2 points as well:

  1. The client should establish a session before sending the authorization request (maybe a /start_login endpoint) and validate that session at the catch_repsonse
  2. Both endpoints should be CORS protected, so that malicious sites cannot establish sessions or read their responses

Comments (5)

  1. adam strickland reporter

    Hi Nat, adding some more research here. CSRF is a pain point for modern SPAs. The csurf module, for instance, was deprecated due to misuse and the low relevance for SPAs.

    The attack I’m envisioning is the following:

    1. A single page app tries to use the code snippet in 15.5.3 above, and is relying on CORS as their main CSRF protection
    2. An attacker has the browser navigate directly to catch_response as a form POST, including the attacker’s auth code. If the SPA’s server is setting a cookie in response to this request, the user will be logged in as the attacker. This only works because the catch_response is a simple request that can be invoked with a page navigation
    3. The catch_response likely won’t return HTML, and the user will likely close the page in confusion. Back at the attacker’s site, you show one more link to the target app’s main page, which should render as if the user is logged in (as the attacker)

    I tried to replicate what Angular does, where you set a cookie that JS can read containing a CSRF token. This video is a good overview. I implemented a simple non-login example here, using express and vanilla JS/HTML.

    To translate that to OAuth 2.0, I did the following here:

    • Replace “XSRF-TOKEN“ cookie with an “AUTHORIZE-REQUEST” cookie, which contained the full authorize request URL. The SPA will read this and navigate the browser to it
    • Replaced the “X-XSRF-TOKEN” request header with an “X-AUTHORIZE-RESPONSE” header, which contains the query string of the authorize response. On redirect, the SPA reads this from the URL and forwards it down to the server

  2. Michael Jones
    • removed milestone

    Establishing a new start_login endpoint would be new incompatible spec work and not an errata action. Is there a specific change that you’d recommend for the example that doesn’t require new protocol features?

  3. adam strickland reporter

    Hi Michael, I was not trying to say that start_login should be added to a spec. Rather, I’m trying to say the example client application, where we arbitrarily have some implementation details, should have a couple more details added to be a complete implementation.

    In section 15.5.3, we have an arbitrarily named catch_response endpoint that fulfills some of what the client is responsible for, and that isn’t defined in any spec. I’m trying to say we should add a second endpoint called start_login, and have it meet the requirements above to be a complete implementation. Does that make sense?

  4. Michael Jones

    Kind of. Could you propose specific complete text for the example that you would like the current example to be updated with? Thanks.

  5. Log in to comment