1

I recently completed Azure OAuth2 integration with my existing web application. Upon user's successful login into my application user can configure multiple outlook accounts using OAuth2 flow.

As for CSRF prevention for my web application I am already generating a random, unique UUID which is used CSRF token. And for OAuth2 request we have state parameter which is can also be used for CSRF prevention for OAuth flow.

Now while implementing OAuth flow I have used the same CSRF token for state parameter and on response from provider I am cross checking the state param with session's CSRF token.

But, the security team is saying the CSRF token should not be shared with third-parties in this case it's OAUth provider and should be secret. Which I don't think it's make sense, because within web app if you look at other (non-oauth) requests then the CSRf token is the part of request header. That means it is not secret as anyone can see it if they intercept the request.

Is my thinking correct? and is there any security risk to using existing CSRF token for state param or sharing it with third party (Oauth provider in this case)?

1 Answer 1

1

Which I don't think it's make sense, because within web app if you look at other (non-oauth) requests then the CSRf token is the part of request header. That means it is not secret as anyone can see it if they intercept the request.

The risk isn't interception of the request. That is approximately never a thing you have to worry about, so long as you use modern TLS (generally via HTTPS) and don't mess with the certificate validation. The problem with sending the anti-CSRF token in the OAuth request is that you are taking something that's supposed to be first-party only (well, and second-party, I guess: it's known to you, and your user, but nobody else) and adding a third party (the OAuth authorization provider). There's no interception here; you're just straight up giving it to somebody else.

Now, at first glance, it seems that this isn't an issue anyhow. Assuming that you're using OAuth for creating user sessions or accessing their data, you must already must completely trust the OAuth provider! If they're malicious (or compromised), they can just create an access token for any of your users, without the actual user being involved at all. Given that fact, hiding the user's anti-CSRF token from the OAuth provider is meaningless; either your OAuth provider is trustworthy, or every one of your users is completely screwed (and CSRF is an attack on the user, not on the site operator). Session forgery strictly dominates CSRF in terms of what you can do with it!

With all that said, there is still a downside to using the anti-CSRF token this way: OAuth requests (and typically also the callbacks) are made using GET requests, with all the parameters in the URL. Since URLs are often logged and the logs are often neither sufficiently redacted nor stored as securely as secrets should be, it is important to not put persistent secrets into the URL. Even the authorization code (for OAuth flows that have one) is on thin ice; it's supposed to be short-lived and single-use, but ideally it wouldn't be transmitted in a URL at all (and indeed, some OAuth providers allow sending the callback secrets via a POST request body, rather than in the URL). The anti-CSRF token is presumably a persistent secret, lasting for at least the length of the session.

One simple fix here - which you should be doing anyhow - is to rotate the anti-CSRF token after the OAuth flow completes. That is, when the user's browser (or similar client) sends the callback request - with its state parameter, and also its temporary session token or whatever else you use to tie the anti-CSRF token to the user - just validate the state parameter and then invalidate that anti-CSRF token, generate a new one, and send the new one to the client. In fact, assuming you're using OAuth for user session initiation, you MUST already rotate the pre-auth session token (or whatever you're using to tie a user to their anti-CSRF token) upon the user logging in via OAuth - that's just standard prevention of session fixation attacks, you never preserve a session token across authentication changes - so you might as well rotate the anti-CSRF token at the same time.

Note that, if you're using OAuth for single sign-in or other session initiation, unless you're worried about login CSRF (which most sites don't prevent, and is hard to fully mitigate anyhow), you mostly only need to worry about OAuth CSRF when linking an OAuth-connected account to an existing app-specific account. That's generally the only time that the user is already signed in while doing an OAuth flow. For a user that isn't signed in, CSRF generally isn't a big risk (although there are edge cases with e.g. stateful data stored in cookies, in lieu of server-side sessions, being manipulated by unauthenticated requests to the server; those requests could be forged instead of user-initiated. That whole scenario is fairly rare, though).

4
  • Thanks for detailed answer. By reading your answer I get sense that why CSRF token should be secret and not be shared with third-party (who is not trustworthy). But using it for state parameter is not a "security" risk or at least I don't see any possible attack enabled by it, do you? Because there is no way to get anyone's CSRF token unless malicious user has put something (script/application) at victim's side, which will read the request headers. So not sharing CSRF token with third party will be a recommendation rather than "security" vulnerability (?)
    – Amogh
    Jan 2 at 14:17
  • If you use the anti-CSRF token as the state param, it will end up in URLs and therefore potentially in logs, where if somebody untrustworthy can read the logs, they will learn your user's anti-CSRF token and can potentially cause that user to forge authenticated requests. The attacker doesn't need to read the request headers if the victim has just left the token lying in a logfile somewhere! Mind you, depending on exactly how your CSRF protection works, it's possible to make the token non-secret, but since you're using a secure random one, you should not expose it.
    – CBHacking
    Jan 3 at 0:14
  • "they will learn your user's anti-CSRF token and can potentially cause that user to forge authenticated requests." --> How one can learn about UUID generation? I mean we are generating CSRF token using UUID mechanism which is random, so how could any one guess the next generation of toekn. And Also If someone gets some user's current CSRF token (by looking at server/browser logs) then how attacker able to perform CSRf attack with have using session, when session anti-hijacking is in place.
    – Amogh
    Jan 5 at 14:24
  • OK, first things first, UUIDs as a category are not guaranteed unpredictable, only unique. V4 UUIDs are guaranteed random but you're still using the wrong tool for the job. Second, why wouldn't an attacker, who has a user's current anti-CSRF token, be able to perform a CSRF attack? The whole point of an anti-CSRF token is that if the attacker doesn't know it, they can't do a CSRF attack; it logically follows that if they do know it, they may be able to do a CSRF attack. You don't need session hijacking; it's the victim's own browser submitting the attacker's forged requests.
    – CBHacking
    Jan 6 at 6:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .