Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0f2c21c

Browse files
committed
python: require local protection to be absent
for CSRF to be likely
1 parent f5b5308 commit 0f2c21c

4 files changed

Lines changed: 59 additions & 3 deletions

File tree

python/ql/lib/semmle/python/Concepts.qll

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ module FileSystemWriteAccess {
106106
}
107107

108108
/**
109-
* A data-flow node that may set or unset Cross-site request forgery protection.
109+
* A data-flow node that may set or unset Cross-site request forgery protection
110+
* in a global manner.
110111
*
111112
* Extend this class to refine existing API models. If you want to model new APIs,
112113
* extend `CSRFProtectionSetting::Range` instead.
@@ -122,7 +123,8 @@ class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSett
122123
/** Provides a class for modeling new CSRF protection setting APIs. */
123124
module CSRFProtectionSetting {
124125
/**
125-
* A data-flow node that may set or unset Cross-site request forgery protection.
126+
* A data-flow node that may set or unset Cross-site request forgery protection
127+
* in a global manner.
126128
*
127129
* Extend this class to model new APIs. If you want to refine existing API models,
128130
* extend `CSRFProtectionSetting` instead.
@@ -136,6 +138,39 @@ module CSRFProtectionSetting {
136138
}
137139
}
138140

141+
/**
142+
* A data-flow node that provides Cross-site request forgery protection
143+
* for a specific part of an application.
144+
*
145+
* Extend this class to refine existing API models. If you want to model new APIs,
146+
* extend `CSRFProtection::Range` instead.
147+
*/
148+
class CSRFProtection extends DataFlow::Node instanceof CSRFProtection::Range {
149+
/**
150+
* Gets a `Function` representing the protected interaction
151+
* (probably a request handler).
152+
*/
153+
Function getProtected() { result = super.getProtected() }
154+
}
155+
156+
/** Provides a class for modeling new CSRF protection setting APIs. */
157+
module CSRFProtection {
158+
/**
159+
* A data-flow node that provides Cross-site request forgery protection
160+
* for a specific part of an application.
161+
*
162+
* Extend this class to model new APIs. If you want to refine existing API models,
163+
* extend `CSRFProtection` instead.
164+
*/
165+
abstract class Range extends DataFlow::Node {
166+
/**
167+
* Gets a `Function` representing the protected interaction
168+
* (probably a request handler).
169+
*/
170+
abstract Function getProtected();
171+
}
172+
}
173+
139174
/** Provides classes for modeling path-related APIs. */
140175
module Path {
141176
/**

python/ql/lib/semmle/python/frameworks/Django.qll

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,3 +2346,20 @@ module PrivateDjango {
23462346
}
23472347
}
23482348
}
2349+
2350+
private class DjangoCSRFDecorator extends CSRFProtection::Range {
2351+
Function function;
2352+
2353+
DjangoCSRFDecorator() {
2354+
this =
2355+
API::moduleImport("django")
2356+
.getMember("views")
2357+
.getMember("decorators")
2358+
.getMember("csrf")
2359+
.getMember("csrf_protect")
2360+
.getAUse() and
2361+
this.asExpr() = function.getADecorator()
2362+
}
2363+
2364+
override Function getProtected() { result = function }
2365+
}

python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ import python
1515
import semmle.python.Concepts
1616

1717
from CSRFProtectionSetting s
18-
where s.getVerificationSetting() = false
18+
where
19+
s.getVerificationSetting() = false and
20+
not exists(CSRFProtection p)
1921
select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened."

python/ql/test/library-tests/frameworks/django-v2-v3/response_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound
22
from django.views.generic import RedirectView
3+
from django.views.decorators.csrf import csrf_protect
34
import django.shortcuts
45
import json
56

@@ -117,6 +118,7 @@ class CustomJsonResponse(JsonResponse):
117118
def __init__(self, banner, content, *args, **kwargs):
118119
super().__init__(content, *args, content_type="text/html", **kwargs)
119120

121+
@csrf_protect
120122
def safe__custom_json_response(request):
121123
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
122124

0 commit comments

Comments
 (0)