-
Notifications
You must be signed in to change notification settings - Fork 652
Add CSRF_COOKIE to prevent csrf when using JWT_AUTH_COOKIE #434
base: master
Are you sure you want to change the base?
Conversation
To prevent Cross-Site Request Forgery when using JWT_AUTH_COOKIE, the `csrftoken` cookie will also be set when issuing the JWT authentication token.
Codecov Report
@@ Coverage Diff @@
## master #434 +/- ##
==========================================
- Coverage 90.67% 90.13% -0.54%
==========================================
Files 14 12 -2
Lines 847 821 -26
Branches 29 30 +1
==========================================
- Hits 768 740 -28
- Misses 66 67 +1
- Partials 13 14 +1
Continue to review full report at Codecov.
|
I think this changes are not enough for CSRF protection when JWT_AUTH_COOKIE option is enabled. Your patch adds csrf cookie, but looks like it's value will be never checked, because django-rest-framework explicitly wraps every view in csrf_exempt(). https://github.com/encode/django-rest-framework/blob/master/rest_framework/views.py#L134 I believe that BaseJSONWebTokenAuthentication authentication class should enforce csrf validation when needed. Like in rest_framework.authentication.SessionAuthentication, which explicitly call CSRFCheck? |
Hi @yurikulaz, actually, with this patch the csrf value will be checked for every method that you explicitly declare you want checked. For example, you can try with Nevertheless, enforcing the csrf check by default and declaring exemptions explicitly is the safer way to code. I'll definitely look into adding that too. |
@bmpenuelas Thanks for writing this patch! Is this PR a comprehensive fix (with using the csrf decorator)? Is there any reason why I shouldn't make a custom |
Yes @jheld , using the csrf decorator, this fix alone can provide the desired protection. |
Does this protect against login csrf? |
@paul110590 CSRF implies that the attack is executed from another domain, if you want to know whether if the user login is protected then yes, the malicious domain cannot read the CSRF token which belongs to your domain, and thus, the request will fail. |
Hi @bmpenuelas , what I mean is the CSRF token is not set until the JWT is issued, i.e. after the user has logged in. Therefore an attacker could log in via CSRF and the user would think they were logged in to their own account. The user would then unwittingly be performing actions on the attacker's account. Or is there some protection against this that I am missing? |
Protection is generally geared toward avoiding forging user requests. That protection is provided by the Anti-CSRF token and the JWT token working together. In the particular case you mention, at no time is the user session compromised. It's not a threat like user-impersonating CSRF, but it's true it can have privacy implications. I don't want to go off-topic here since this isn't related to the pull-request itself, but CSRFToken can protect your application from this situation too. For example, you can issue an Anti-CSRF token for the login process, and store it as both: a hidden form value, and a cookie. To validate the login request, both values must match, and since an attacker can't read them both, the login will fail. |
It's a different type of csrf to the more common session riding, but it's still a security flaw we need to protect against. This is where I think it has relevancy to the pull request: To protect against login-csrf we need to decorate our login view with csrf_protect. We then need to create a view that will set the csrftoken cookie, so that we can fetch it prior to login and our login request is not blocked. This being the case, we no longer need to set the csrftoken cookie when we issue the JWT, because it is already set. Basically, if we follow the approach of protecting ourselves from login-csrf we will also automatically be protecting ourselves from 'normal' csrf (provided we guard all unsafe views with csrf_protect). Whereas if we follow the approach of protecting from 'normal' csrf, we are still leaving ourselves open to login-csrf. |
Yes, this PR already does that. CSRF tokens are issued for every request, not only after login, so you can use them for login, or to protect other requests, the same principles apply. The problem before this PR was that when you used the JWT token for authentication, the CSRF token was ignored. |
@@ -3,6 +3,8 @@ | |||
from rest_framework.response import Response | |||
from datetime import datetime | |||
|
|||
from django.middleware import csrf |
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.
just a consideration as I saw this referred to at Styria-Digital#4 , maybe it is appropriate to only import this if api_settings.CSRF_COOKIE
is enabled, e.g. as a delayed import within the if
below.
Then any site not using csrf middleware doesnt get hit with an extra module being import that isnt used. Are there many sites doing that?
Also pep8 tools would complain bitterly about that.
Any ideas when this PR is going to be merged into the package? Does it need work, can I help in any way getting this out the door? |
We should hope not. Maybe we can ask for maintainer privileges? Including PyPI. We've been waiting for this fix for a year. |
To prevent Cross-Site Request Forgery when using JWT_AUTH_COOKIE, the
csrftoken
cookie will also be set when issuing the JWT authentication token.