mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
python: broaden local protection concept
This commit is contained in:
@@ -123,7 +123,7 @@ class CsrfProtectionSetting extends DataFlow::Node instanceof CsrfProtectionSett
|
|||||||
/** Provides a class for modeling new CSRF protection setting APIs. */
|
/** Provides a class for modeling new CSRF protection setting APIs. */
|
||||||
module CsrfProtectionSetting {
|
module CsrfProtectionSetting {
|
||||||
/**
|
/**
|
||||||
* A data-flow node that may set or unset Cross-site request forgery protection
|
* A data-flow node that enables or disables Cross-site request forgery protection
|
||||||
* in a global manner.
|
* in a global manner.
|
||||||
*
|
*
|
||||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||||
@@ -139,35 +139,39 @@ module CsrfProtectionSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data-flow node that provides Cross-site request forgery protection
|
* A data-flow node that enables or disables Cross-site request forgery protection
|
||||||
* for a specific part of an application.
|
* for a specific part of an application.
|
||||||
*
|
*
|
||||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||||
* extend `CsrfLocalProtection::Range` instead.
|
* extend `CsrfLocalProtectionSetting::Range` instead.
|
||||||
*/
|
*/
|
||||||
class CsrfLocalProtection extends DataFlow::Node instanceof CsrfLocalProtection::Range {
|
class CsrfLocalProtectionSetting extends DataFlow::Node instanceof CsrfLocalProtectionSetting::Range {
|
||||||
/**
|
/**
|
||||||
* Gets a `Function` representing the protected interaction
|
* Gets a request handler whose CSRF protection is changed.
|
||||||
* (probably a request handler).
|
|
||||||
*/
|
*/
|
||||||
Function getProtected() { result = super.getProtected() }
|
Function getRequestHandler() { result = super.getRequestHandler() }
|
||||||
|
|
||||||
|
/** Holds if CSRF protection is enabled by this setting */
|
||||||
|
predicate csrfEnabled() { super.csrfEnabled() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Provides a class for modeling new CSRF protection setting APIs. */
|
/** Provides a class for modeling new CSRF protection setting APIs. */
|
||||||
module CsrfLocalProtection {
|
module CsrfLocalProtectionSetting {
|
||||||
/**
|
/**
|
||||||
* A data-flow node that provides Cross-site request forgery protection
|
* A data-flow node that enables or disables Cross-site request forgery protection
|
||||||
* for a specific part of an application.
|
* for a specific part of an application.
|
||||||
*
|
*
|
||||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||||
* extend `CsrfLocalProtection` instead.
|
* extend `CsrfLocalProtectionSetting` instead.
|
||||||
*/
|
*/
|
||||||
abstract class Range extends DataFlow::Node {
|
abstract class Range extends DataFlow::Node {
|
||||||
/**
|
/**
|
||||||
* Gets a `Function` representing the protected interaction
|
* Gets a request handler whose CSRF protection is changed.
|
||||||
* (probably a request handler).
|
|
||||||
*/
|
*/
|
||||||
abstract Function getProtected();
|
abstract Function getRequestHandler();
|
||||||
|
|
||||||
|
/** Holds if CSRF protection is enabled by this setting */
|
||||||
|
abstract predicate csrfEnabled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2356,20 +2356,24 @@ module PrivateDjango {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DjangoCsrfDecorator extends CsrfLocalProtection::Range {
|
private class DjangoCsrfDecorator extends CsrfLocalProtectionSetting::Range {
|
||||||
|
string decoratorName;
|
||||||
Function function;
|
Function function;
|
||||||
|
|
||||||
DjangoCsrfDecorator() {
|
DjangoCsrfDecorator() {
|
||||||
|
decoratorName in ["csrf_protect", "csrf_exempt", "requires_csrf_token", "ensure_csrf_cookie"] and
|
||||||
this =
|
this =
|
||||||
API::moduleImport("django")
|
API::moduleImport("django")
|
||||||
.getMember("views")
|
.getMember("views")
|
||||||
.getMember("decorators")
|
.getMember("decorators")
|
||||||
.getMember("csrf")
|
.getMember("csrf")
|
||||||
.getMember("csrf_protect")
|
.getMember(decoratorName)
|
||||||
.getAUse() and
|
.getAUse() and
|
||||||
this.asExpr() = function.getADecorator()
|
this.asExpr() = function.getADecorator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override Function getProtected() { result = function }
|
override Function getRequestHandler() { result = function }
|
||||||
|
|
||||||
|
override predicate csrfEnabled() { decoratorName in ["csrf_protect", "requires_csrf_token"] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import semmle.python.Concepts
|
|||||||
from CsrfProtectionSetting s
|
from CsrfProtectionSetting s
|
||||||
where
|
where
|
||||||
s.getVerificationSetting() = false and
|
s.getVerificationSetting() = false and
|
||||||
not exists(CsrfLocalProtection p) and
|
not exists(CsrfLocalProtectionSetting p | p.csrfEnabled()) and
|
||||||
// rule out test code as this is a common place to turn off CSRF protection
|
// rule out test code as this is a common place to turn off CSRF protection
|
||||||
not s.getLocation().getFile().getAbsolutePath().matches("%test%")
|
not s.getLocation().getFile().getAbsolutePath().matches("%test%")
|
||||||
select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened."
|
select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened."
|
||||||
|
|||||||
@@ -520,18 +520,20 @@ class CsrfProtectionSettingTest extends InlineExpectationsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CsrfLocalProtectionTest extends InlineExpectationsTest {
|
class CsrfLocalProtectionSettingTest extends InlineExpectationsTest {
|
||||||
CsrfLocalProtectionTest() { this = "CsrfLocalProtectionTest" }
|
CsrfLocalProtectionSettingTest() { this = "CsrfLocalProtectionSettingTest" }
|
||||||
|
|
||||||
override string getARelevantTag() { result = "CsrfLocalProtection" }
|
override string getARelevantTag() { result = "CsrfLocalProtection" + ["Enabled", "Disabled"] }
|
||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
exists(location.getFile().getRelativePath()) and
|
exists(location.getFile().getRelativePath()) and
|
||||||
exists(CsrfLocalProtection p |
|
exists(CsrfLocalProtectionSetting p |
|
||||||
location = p.getLocation() and
|
location = p.getLocation() and
|
||||||
element = p.toString() and
|
element = p.toString() and
|
||||||
value = p.getProtected().getName().toString() and
|
value = p.getRequestHandler().getName().toString() and
|
||||||
tag = "CsrfLocalProtection"
|
if p.csrfEnabled()
|
||||||
|
then tag = "CsrfLocalProtectionEnabled"
|
||||||
|
else tag = "CsrfLocalProtectionDisabled"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class CustomJsonResponse(JsonResponse):
|
|||||||
def __init__(self, banner, content, *args, **kwargs):
|
def __init__(self, banner, content, *args, **kwargs):
|
||||||
super().__init__(content, *args, content_type="text/html", **kwargs)
|
super().__init__(content, *args, content_type="text/html", **kwargs)
|
||||||
|
|
||||||
@csrf_protect # $CsrfLocalProtection=safe__custom_json_response
|
@csrf_protect # $CsrfLocalProtectionEnabled=safe__custom_json_response
|
||||||
def safe__custom_json_response(request):
|
def safe__custom_json_response(request):
|
||||||
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
|
return CustomJsonResponse("ACME Responses", {"foo": request.GET.get("foo")}) # $HttpResponse mimetype=application/json MISSING: responseBody=Dict SPURIOUS: responseBody="ACME Responses"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user