OK, I don't think we're going to agree on all the points here, and this thread is getting really long. Let me try to summarise and see if there is a way forward.
The attack: In the case of a CSRF attack against the auth code flow, detected via the "state" parameter, the auth code remains unused and valid. If an attacker can observe that auth code then they can use it themselves - they can control the state and PKCE in the CSRF attack, so those are not sufficient countermeasures. (CSRF attack here basically just means getting the user to click on a link, as the authorization endpoint allows cross-origin requests by design). The main risks that the code might be exposed are: R1. In logs on the server or any intermediary, where attacker has (near-)real-time access to the logs R2. If the client doesn't scrub the URL after the error and the user then subsequently copy+pastes it to the attacker R3. Referer/window.referrer leakage if the client is explicitly opting in to this (i.e., explicitly downgrading the Referrer-Policy - seems unlikely to me). R4. Third-party scripts (eg analytics) on the callback page. (Not a recommended practice, but probably does happen). The proposed solutions are: S1. Use response_mode=fragment * Addresses R1 (fragment is not sent to server) and R3 (fragment is not included in Referer) * Doesn't address R2, in fact may make it worse (need to explicitly include a new fragment in a redirect to get rid of it - see https://www.ietf.org/rfc/rfc9700.html#name-redirect-uri-validation-atta) * Partially addresses R4 in that analytics providers don't store the fragment by default. * Requires client-side Javascript. S2. Use response_mode=form-post * Addresses R1 (servers normally don't log POST body) and R3 (post data not included in Referer) * Addresses R2 as data is not in the URL at all, and not visible to the user. * Addresses R4 too, as analytics scripts also will not collect POST body either. * Requires client-side Javascript and SameSite=none cookies (if storing the state in a cookie, as is common). (S1 and S2 are both vulnerable to downgrade attacks as the attacker can change it to response_mode=query - would need AS to actively block query response). S3. Ensure auth code is invalidated in case of detected CSRF. S3a: Client carries out exchange as normal but then revokes the tokens immediately (eg via token revocation endpoint, if supported, or maybe just by replaying the auth code itself). S3b: Client uses PKCE and relies on the AS revoking the auth code in case of PKCE verifier mismatch. Requires AS to enforce PKCE, otherwise downgrade possible again. * Addresses all risks by explicitly ensuring code/tokens are invalidated in case of CSRF. * Requires change of client behaviour. * May not actually work if AS doesn't implement revocation properly/enforce PKCE etc. S4. Accept the risk, maybe tighten up wording to clarify the risks: eg sanitise logs, use short auth code lifetimes, always scrub code from URL even in error cases. * Relies on existing countermeasures and assume short lifespan of code is adequate protection for the level of risk. * Do the people who'd need to implement these countermeasures (eg web server/proxy admins) read security considerations for new OAuth specs? Probably not... I think you have convinced me that S4 is probably not sufficient. I'm not convinced that S1 or S2 are good solutions, although I could maybe get on board for S2. S3 is probably the best technical solution, ensuring the code is invalidated. However, it seems like a lot of changes across the ecosystem would be needed, which does seem a lot given the (IMO) low risk of this ever being exploited. Are there other alternatives? PAR (with client auth) would prevent the CSRF attack (again, if enforced by the AS), and I think JAR would too - i.e, preventing the CSRF by strongly authenticating auth requests. Best wishes, Neil
_______________________________________________ OAuth mailing list -- [email protected] To unsubscribe send an email to [email protected]
