mirror of
https://github.com/github/codeql.git
synced 2025-12-23 12:16:33 +01:00
python: minimal CSRF implementation
- currectly only looks for custom django middleware
This commit is contained in:
@@ -105,6 +105,37 @@ module FileSystemWriteAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that may set or unset Cross-site request forgery protection.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `CSRFProtectionSetting::Range` instead.
|
||||
*/
|
||||
class CSRFProtectionSetting extends DataFlow::Node instanceof CSRFProtectionSetting::Range {
|
||||
/**
|
||||
* Gets the boolean value corresponding to if CSRF protection is enabled
|
||||
* (`true`) or disabled (`false`) by this node.
|
||||
*/
|
||||
boolean getVerificationSetting() { result = super.getVerificationSetting() }
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new CSRF protection setting APIs. */
|
||||
module CSRFProtectionSetting {
|
||||
/**
|
||||
* A data-flow node that may set or unset Cross-site request forgery protection.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `CSRFProtectionSetting` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the boolean value corresponding to if CSRF protection is enabled
|
||||
* (`true`) or disabled (`false`) by this node.
|
||||
*/
|
||||
abstract boolean getVerificationSetting();
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling path-related APIs. */
|
||||
module Path {
|
||||
/**
|
||||
|
||||
@@ -2313,4 +2313,35 @@ module PrivateDjango {
|
||||
.getAnImmediateUse()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Settings
|
||||
// ---------------------------------------------------------------------------
|
||||
/**
|
||||
* A custom middleware stack
|
||||
*/
|
||||
private class DjangoSettingsMiddlewareStack extends CSRFProtectionSetting::Range {
|
||||
List list;
|
||||
|
||||
DjangoSettingsMiddlewareStack() {
|
||||
this.asExpr() = list and
|
||||
// we look for an assignment to the `MIDDLEWARE` setting
|
||||
exists(DataFlow::Node mw, string djangomw |
|
||||
mw.asVar().getName() = "MIDDLEWARE" and
|
||||
DataFlow::localFlow(this, mw)
|
||||
|
|
||||
// check that the list contains at least one reference to `django`
|
||||
list.getAnElt().(StrConst).getText() = djangomw and
|
||||
// TODO: Consider requiring `django.middleware.security.SecurityMiddleware`
|
||||
// or something indicating that a security middleware is enabled.
|
||||
djangomw.matches("django.%")
|
||||
)
|
||||
}
|
||||
|
||||
override boolean getVerificationSetting() {
|
||||
if list.getAnElt().(StrConst).getText() = "django.middleware.csrf.CsrfViewMiddleware"
|
||||
then result = true
|
||||
else result = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp
Normal file
60
python/ql/src/Security/CWE-352/CSRFProtectionDisabled.qhelp
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Cross-site request forgery (CSRF) is a type of vulnerability in which an
|
||||
attacker is able to force a user carry out an action that the user did
|
||||
not intend.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The attacker tricks an authenticated user into submitting a request to the
|
||||
web application. Typically this request will result in a state change on
|
||||
the server, such as changing the user's password. The request can be
|
||||
initiated when the user visits a site controlled by the attacker. If the
|
||||
web application relies only on cookies for authentication, or on other
|
||||
credentials that are automatically included in the request, then this
|
||||
request will appear as legitimate to the server.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A common countermeasure for CSRF is to generate a unique token to be
|
||||
included in the HTML sent from the server to a user. This token can be
|
||||
used as a hidden field to be sent back with requests to the server, where
|
||||
the server can then check that the token is valid and associated with the
|
||||
relevant user session.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
In many web frameworks, CSRF protection is enabled by default. In these
|
||||
cases, using the default configuration is sufficient to guard against most
|
||||
CSRF attacks.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows a case where CSRF protection is disabled by
|
||||
overriding the default middleware stack and not including the one protecting against CSRF.
|
||||
</p>
|
||||
|
||||
<sample src="examples/settings.py"/>
|
||||
|
||||
<p>
|
||||
The protecting middleware was probably commented out during a testing phase, when server-side token generation was not set up.
|
||||
Simply commenting it back in (or remove the custom middleware stack) will enable CSRF protection.
|
||||
</p>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">Cross-site request forgery</a></li>
|
||||
<li>OWASP: <a href="https://owasp.org/www-community/attacks/csrf">Cross-site request forgery</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
19
python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql
Normal file
19
python/ql/src/Security/CWE-352/CSRFProtectionDisabled.ql
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @name CSRF protection weakened or disabled
|
||||
* @description Disabling or weakening CSRF protection may make the application
|
||||
* vulnerable to a Cross-Site Request Forgery (CSRF) attack.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision high
|
||||
* @id py/csrf-protection-disabled
|
||||
* @tags security
|
||||
* external/cwe/cwe-352
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.Concepts
|
||||
|
||||
from CSRFProtectionSetting s
|
||||
where s.getVerificationSetting() = false
|
||||
select s, "Potential CSRF vulnerability due to forgery protection being disabled or weakened."
|
||||
9
python/ql/src/Security/CWE-352/examples/setting.py
Normal file
9
python/ql/src/Security/CWE-352/examples/setting.py
Normal file
@@ -0,0 +1,9 @@
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
# 'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
Reference in New Issue
Block a user