Does checking the state (nounce) in Shopify oAuth flow really add to security?

Highlighted
Shopify Partner
22 0 5

Hi there,

 

Would love some security pro to check my thinking.

 

I understand that the state parameter is used in oAuth to prevent CSFR attacks against the redirect_uri. Or put differently: To let a Shopify app only process redirect responses of the Shopify authorization server (where they send the respective request to) and in the same user agent this request was initiated in.

 

But I cannot see how using the state/nounce within the Shopify Auth flow adds any security.

 

Given

  • That the authorization URL is accessible to logged in shop admins only and
  • that we can verify the "shop" parameter (via hmac) on the callback/redirect and tie any actions to the corresponding shop/user within our app.

 

Am I seeing this right that a CSFR attack could only be carried out by another staff account who can log into the same shop (in which case there really is no need to carry out a CSFR in the first place)?

 

What am I missing here?

 

Thanks for helping me understand this.

Dominik

1 Like
Highlighted
Shopify Partner
1781 211 370

This is part of the OAuth specification - https://tools.ietf.org/html/rfc6819#section-3.6. Basically, the "state" parameter links the request and the callback one to one, so there is no way for an attacker (man in the middle or social engineering, that can see the URL as is) to resend/replay the request (callback) The value of the nonce is unique per each request, in case of Shopify, each authorization request.

Sergiu Svinarciuc | CTO @ visely.io
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
- To learn more about the awesome stuff we do head over to visely.io or our blog
0 Likes
Highlighted
Shopify Partner
22 0 5

I appreciate the time you took to write this comment.

Unfortunately, you just repeated the basis for my questions (even using the same link as I did in my question) without addressing my question at all.

 

 

 

 

 

0 Likes
Highlighted
Shopify Partner
1781 211 370

The link is to a different section :) which explains the request/callback pair and the role of the "state" parameter. I have tried to answer your question to my best knowledge, but probably somehow obscure.

Sergiu Svinarciuc | CTO @ visely.io
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
- To learn more about the awesome stuff we do head over to visely.io or our blog
0 Likes
Highlighted
Shopify Partner
22 0 5

I 'll try to rephrase:

 

My question is specific to the Shopify oauth flow. I think I understand why the state parameter is there in general and how it should work in a general context.

That is why I wrote: 

I understand that the state parameter is used in oAuth to prevent CSFR attacks against the redirect_uri.

But Shopify's auth flow is special in that it is completely scoped to a single shopIt is that idiosyncrasy, that gave rise to my question.

 

 

My question is:

If we verify the signed shop parameter in the callback (the redirect_uri), isn't that just as effective as using the state parameter to prevent CSRF attacks?

 

Reasoning:

A CSRF attack could only be carried out by another staff/shop member in which case there really is no need to carry out a CSFR in the first place.

 

I was hoping to find/get an answer along the lines of: "Yes, it is" or "No it is not, because [...]" 

 

Hope that makes things clearer.

Thanks again for your time.

 

Dominik

 

1 Like
Highlighted
Shopify Partner
1781 211 370

A CSRF attack could only be carried out by another staff/shop member

As mentioned in my first reply, a man in the middle attack can also make your store vulnerable isn't it?

 

If we verify the signed shop parameter in the callback (the redirect_uri), isn't that just as effective as using the state parameter to prevent CSRF attacks?

Assume you don't send a nonce, how can you tell the request that you get originates from Shopify and is not a "replayed" URL? The signature is going to be valid as the original URL redirect Shopify has sent you was legit, recorded and "replayed" by the attacker.

 

If you send a nonce that is unique per request and you know (by keeping a record of the unique nonce for each request/callback cycle) that this nonce was already used, you can tell the request has been forged.

 

How exploitable is this - is another question :)

Sergiu Svinarciuc | CTO @ visely.io
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
- To learn more about the awesome stuff we do head over to visely.io or our blog
1 Like
Highlighted
Shopify Partner
22 0 5

OK, thanks - this was helpful. While my questions was about CSRF you pointed out that a play attack could also happen.

But I am still having problems to see the problem there:

 

Let say a bad actor (Alice) intercepts and replays a victim's (Bob at bob.ymshopify.com) authorizatinon URL. What bad could happen there? Is my understanding correct that, as the authorisation url is at https://bob.myshopify.com/admin/oauth/authorize and this tied to Bob's shop, only a staff members (users already having access to Bob's shop) could carry out such an attack?

 

If that assumption is correct my thinking was: If Alice already has access to Bobs shop there really is no need to attack the auth flow.

 

Am I missing something here? Thanks for your help.

 

EDIT: Wait, I am mixing up things here, sorry. You were talking about replaying the redirect_uri - I need to think this through again ;-)

 

0 Likes
Highlighted
Shopify Partner
22 0 5

After thinking/reading a bit, I think my confusion stems from blurring the concepts of state and nonce.

 

Can a replay attack really succeed when shopify is (as it should be, according to the spec) allowing each code (the authorisation code) parameter to be used once only. So replaying the redirect_uri could not be used to obtain another access token.

 

Is the state parameter really concerned with replay attacks?

 

EDIT:

  1. As I understand it, using the state parameter, as recommended in the documentation, does not prevent a request to be replayed within the same user agent. It says the state parameter should be unique for each authorization request, not to keep a history of state parameters or even just to reset them on the client after a successful check in the callback. For instance, when it comes to the official Shopify boilerplate apps only shopify_app resets the state parameter (deletes it from the session) after a callback has been processed (well, omniauth-oauth2 does) while koa-auth-shopify does not (it seems). So there really is nothing preventing a replay of the same request within the same browser. I guess this is not a problem since we are not transferring money or something like that, but still - isn't that a replay attack?
  2. Just to make sure I checked and, as expected, Shopify will not issue an access token when the authorization code has already been used.
  3. When there is social engineering or a man-in-the-middle going on, I guess the initial request from the client to the  authorization server could be intercepted the same way, thus rendering the state parameter useless?

 

0 Likes
Highlighted
Trailblazer
139 13 24

I have the same confusion about nonces, though I think I need a more basic explanation. Who is the potential victim here - us as the app developer (merchants somehow installing our apps for free), or the Shopify merchant that is trying to install our app (an attacker intercepting the auth code and exchanging it for an access token before we do it)?  

 

If the attacker gets the code before we do and we can't exchange it since it's already been used, what action do we take at that point?

 

It seems based on the documentation that if the state doesn't match in the redirect, you just... don't send the auth code over to exchange for the access token? But at that point your app is installed anyway, right? And what is the harm at that point of exchanging the access token, given that you'll be sending the request to {shopOrigin}/admin/oauth/access_token - not the attacker's own server?

 

I'm clearly confused and appreciate anyone's help in helping my understanding. Thanks!

0 Likes