-
Notifications
You must be signed in to change notification settings - Fork 683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Skip CSRF check if a valid JWT is passed in #994
Conversation
LGTM but would be nice to figure out how to write a test around it. |
|
||
private | ||
|
||
def jwt_shopify_domain? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we name this something that describes what it's telling us? like session_token_auth?
or valid_session_token_header?
or something?
We noticed that this PR modifies the behaviour of CSRF tokens in this application. Our team will take a look soon, but for now please consider what the best CSRF behaviour for your application is. If the controller in question is meant to be used mostly as an API by non-browser clients, a sane option is |
@ragalie Unfortunately, there's no easy way to simulate the whole CSRF test flow. |
b0e22eb
to
141a5b5
Compare
Another thought: I think we're explicitly trying to get away from requiring people to subclass Can we move this into the module? |
@ragalie Sure we can do that. |
141a5b5
to
b75299e
Compare
caf27a4
to
7825bc6
Compare
# frozen_string_literal: true | ||
module ShopifyApp | ||
module CsrfProtection | ||
extend ActiveSupport::Concern |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're using ActiveSupport::Concern
, you can just include LoginProtection
here. You don't need to do the ancestors check.
See https://api.rubyonrails.org/classes/ActiveSupport/Concern.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that's a good idea. CsrfProtection
should ideally have nothing to do with LoginProtection
. They serve different purposes. If you want, I can have CsrfProtection
access the jwt_shopify_domain
directly from the request environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the middleware exposes that interface right now, so it doesn't bother me if you access the env
directly.
My feedback is that under the current approach you have a dependency on LoginProtection
, and it's better to use the tools that ActiveSupport::Concern
gives you to enforce that dependency than to build your own thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to do something more duck-typing-esque? Like, put some defensive code around the reference to jwt_shopify_domain
to raise a meaningful error if it's not present?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, personally. IMO the interface is the keys added to the env
. We can either access that interface directly or we can pull in a method we know accesses the interface correctly.
The jwt_shopify_domain
method is not the interface and testing that a jwt_shopify_domain
method of unknown origin is present is the wrong approach IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is we don't know if the app is using JWT or cookie based auth (Especially due to the fallbacks where it can use either). So we default to the standard Rails CSRF error.
Nice tests! Good stuff! |
2d9f1e4
to
d45a26a
Compare
d45a26a
to
274f194
Compare
I'm getting an invalid CSRF token on a form submission in an embedded, multi-page app, using jwt authentication and turbolinks. I figured this PR would have fixed it but no luck. When checking for Authentication seems to work fine otherwise. This is a separate controller from my home controller doing basic CRUD stuff. I'm inheriting from ApplicationController, I'm including I'm on the most recent version of the shopify_app engine, I've followed the documentation, searched the community, and looked carefully through the jwt example app. I'm at a loss for what I could be doing wrong. Any help would be very appreciated. @theundeadmonk Figured I'd tag you since you seem to be very knowledgable on this subject. Thanks so much for your time! Edit: Forgot to mention the invalid CSRF token error is only happening in incognito mode, but this is how the app reviewer is testing my app, so I have to make it work there. |
Hi @dianedouglas-thrive. The separate controller mentioned should include the If you have more questions or info, feel free to log a GitHub issue and we can keep track of it there. |
Hi @rezaansyed, thanks so much for the info! I'll give that a try and if I have any further problems I'll make a separate github issue. Once I get this figured out I can also try to make a PR to help with the documentation on this issue. 2 quick questions if you wouldn't mind clarifying please:
Thanks again for your time. |
Hi @rezaansyed - sorry to bug you again but I'm still having issues. I can open a separate issue if you like, but wanted to make sure I'm not missing some small step. If I
This happens on any controller action, regardless of incognito mode or not. I also tried to instantiate the AppBridge using this code:
Is this correct? Do I specifically need to add a hidden field or something to include |
@dianedouglas-thrive no problem! To answer your questions:
|
@dianedouglas-thrive can you open a new issue for this. It will be easier to track and support the problems you're running into. |
Will do, thanks! |
@rezaansyed added the issue here: #1219 Also, I looked at the tutorial you mentioned above, I'm not using a splash page but since I used the default shopify_app generator as I understand it I should be using the jwt implementation correctly. However, I think there are two things going on here - one is that I am probably missing something in my controller/views meaning that my jwt is getting lost, but there might also be some incognito mode behavior that might actually be a bug that needs to be addressed. Anyway we can chat more in the other issue. Thanks again! |
With 3p cookies being blocked, Rails will no longer be able to set CSRF tokens. This will result in requests failing with an
invalid CSRF token
error.When using JWT based auth, a valid signed JWT is as secure than a CSRF token, since we trust that Shopify is the only source that can sign it securely.
This PR introduces a new concern that when included, skips the CSRF check if we are able to successfully extract the shop domain from the JWT.