mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +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. */
|
/** Provides classes for modeling path-related APIs. */
|
||||||
module Path {
|
module Path {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2313,4 +2313,35 @@ module PrivateDjango {
|
|||||||
.getAnImmediateUse()
|
.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