Added a CodeQL query and tests for Django CSRF protection check. - #3296
Added a CodeQL query and tests for Django CSRF protection check.#3296Dhayalanb wants to merge 5 commits into
Conversation
RasmusWL
left a comment
There was a problem hiding this comment.
Thanks for your submission ✨ 🚀
I'm quite busy at the moment, so here are a few comments to get this PR moving forwards.
I would also like to see one example for vulnerable and one for not-vulnerable code. Could be great if you could include examples that are using the requires_csrf_token, ensure_csrf_cookie, and csrf_protect decorators.
Please also read our contributing guidelines and make sure you target the PR to add the new query to the experimental directory.
Added code to the query to check for tuples as well and make it more efficient.
RasmusWL
left a comment
There was a problem hiding this comment.
Thanks for updating your PR so fast 👍 I have been super swamped with other things, so thanks for your patience 😊
There are a few things I think we need to fix, but after an iteration or two, we should be ready to merge this query into our experimental set of queries.
One point is that using toString() in the where clause is strictly forbidden by our contributing guidelines (4. Compilation) -- usually it is also an indication of trying to write ql in a non-idiomatic way. Not to worry, we'll sort it out together 😜
|
Removing the automatic request for review by a member of the docs team now that this pull request targets the |
|
Thanks for making these updates! 👍 I ran your query against all python projects on LGTM.com (before the changes in 8b4b3bc), and after looking through some results, I found it quite hard to see if the alert was a real problem (true positive -- TP) or if it actually didn't matter (false positive -- FP). For example:
Do you happen to have an example of this problem in real code? Requirement 5 for submitting a new query says:
Moving this query forwardsI think we have two options. Either we merge this query as-is with a fairly bad FP-rate (should be reflected in the I'm thinking what could really improve this query is if it could highlight the exact location where I should have been using CSRF protection and I didn't. This requires some way to figure out when I should have been using CSRF protection, which is hard to get 100% correct. My intuitive suggestion would be to look for non CSRF protected handling of state-changing HTTP requests such as POST, DELETE, etc., and flag the ones that require being authenticated. This will ignore some useful results, such as (1) wanting to allow form submission from anonymous users only after they visit your webpage, and (2) django applications that use GET requests for state-changes. My intuitive understand is that both would be a fair tradeoff. But the decision is up to you, depending on how enthusiastic you are about working more on this query 😉 |
RasmusWL
left a comment
There was a problem hiding this comment.
A few minor things about the qhelp
| <code> | ||
| @csrf_protect | ||
| def index(request): | ||
| return HttpResponse("Hello, world.") | ||
| </code> |
There was a problem hiding this comment.
Can you turn this into using the <sample src="<name>.py" /> pattern?
I would also like you to substitute the "hello world" example with something that actually requires CSRF protection. Maybe something like this :)
@csrf_protect
def change_password(request):
...| <!DOCTYPE qhelp SYSTEM "qhelp.dtd"> | ||
| <qhelp> | ||
| <overview> | ||
| <p>ACross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions |
There was a problem hiding this comment.
| <p>ACross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions | |
| <p>A Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions |
|
|
||
| <p> When a Django project is created the CSRF middleware is activated by default in the MIDDLEWARE setting, | ||
| thereby providing CSRF protection to all the views. If disabled , which is not recommended, | ||
| csrf_protect() can be used on particular views that needs to be protected</p> |
There was a problem hiding this comment.
| csrf_protect() can be used on particular views that needs to be protected</p> | |
| <code>csrf_protect()</code> can be used on particular views that needs to be protected</p> |
|
|
||
| <sample src="CSRFMiddleware.py" /> | ||
|
|
||
| <p>The corrected version does not include django.middleware.csrf.CsrfViewMiddleware, which |
There was a problem hiding this comment.
| <p>The corrected version does not include django.middleware.csrf.CsrfViewMiddleware, which | |
| <p>The corrected version does not include <code>django.middleware.csrf.CsrfViewMiddleware</code>, which |
|
@Dhayalanb @RasmusWL Do you mind if I take this up? |
|
I'm going to close the PR now due to inactivity. I'm not aware of such instances of a PR getting stale and someone else picking up the threads @porcupineyhairs, can we please take this conversation on the Security Lab slack? 😊 |
When a Django project is created, the CSRF middleware is activated by default in the MIDDLEWARE setting, thereby providing CSRF protection to all the views. It is also possible to disable this to make development easier and unless decorators such as csrf_protect() is used to protect the every single critical views, the application will be vulnerable to Cross-Site Request Forgery (CWE-352).
CSRF Protection can be enabled/ Disabled by adding/ removing the
django.middleware.csrf.CsrfViewMiddlewarefrom the MIDDLEWARE variable.This PR adds a CodeQL query with unit tests, which checks if any forms of CSRF prevention mechanism is enabled.
CSRF mechanism tested:
django.middleware.csrf.CsrfViewMiddlewarein MIDDLEWARE variable.CsrfViewMiddlewareclass