mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Python add new queries for clear-text logging and storage.
This commit is contained in:
5
python/ql/src/Security/CWE-312/CleartextLogging.qhelp
Normal file
5
python/ql/src/Security/CWE-312/CleartextLogging.qhelp
Normal file
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CleartextStorage.qhelp" /></qhelp>
|
||||
41
python/ql/src/Security/CWE-312/CleartextLogging.ql
Normal file
41
python/ql/src/Security/CWE-312/CleartextLogging.ql
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @name Clear-text logging of sensitive information
|
||||
* @description Logging sensitive information without encryption or hashing can
|
||||
* expose it to an attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id py/clear-text-storage-of-sensitive-data
|
||||
* @tags security
|
||||
* external/cwe/cwe-312
|
||||
* external/cwe/cwe-315
|
||||
* external/cwe/cwe-359
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.SensitiveData
|
||||
import semmle.python.security.ClearText
|
||||
|
||||
|
||||
class CleartextLoggingConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
CleartextLoggingConfiguration() { this = "ClearTextLogging" }
|
||||
|
||||
override predicate isSource(TaintSource src) {
|
||||
src instanceof SensitiveData::Source
|
||||
}
|
||||
|
||||
override predicate isSink(TaintSink sink) {
|
||||
sink instanceof ClearTextLogging::Sink
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
from CleartextLoggingConfiguration config, TaintedPathSource source, TaintedPathSink sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getSink(), source, sink, "Sensitive data returned by $@ is stored here.",
|
||||
source.getSource(), source.getNode().(SensitiveData::Source).repr()
|
||||
52
python/ql/src/Security/CWE-312/CleartextStorage.qhelp
Normal file
52
python/ql/src/Security/CWE-312/CleartextStorage.qhelp
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Sensitive information that is stored unencrypted is accessible to an attacker
|
||||
who gains access to the storage. This is particularly important for cookies,
|
||||
which are stored on the machine of the end-user.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Ensure that sensitive information is always encrypted before being stored.
|
||||
If possible, avoid placing sensitive information in cookies altogether.
|
||||
Instead, prefer storing, in the cookie, a key that can be used to look up the
|
||||
sensitive information.
|
||||
</p>
|
||||
<p>
|
||||
In general, decrypt sensitive information only at the point where it is
|
||||
necessary for it to be used in cleartext.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
Be aware that external processes often store the <code>standard
|
||||
out</code> and <code>standard error</code> streams of the application,
|
||||
causing logged sensitive information to be stored as well.
|
||||
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example code stores user credentials (in this case, their password) in a cookie in plain text:
|
||||
</p>
|
||||
<sample src="examples/password_in_cookie.py"/>
|
||||
<p>
|
||||
Instead, the credentials should be encrypted, for instance by using the <code>cryptography</code> module, or not stored at all.
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
40
python/ql/src/Security/CWE-312/CleartextStorage.ql
Normal file
40
python/ql/src/Security/CWE-312/CleartextStorage.ql
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @name Clear-text storage of sensitive information
|
||||
* @description Sensitive information stored without encryption or hashing can expose it to an
|
||||
* attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id py/clear-text-logging
|
||||
* @tags security
|
||||
* external/cwe/cwe-312
|
||||
* external/cwe/cwe-315
|
||||
* external/cwe/cwe-359
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.SensitiveData
|
||||
import semmle.python.security.ClearText
|
||||
|
||||
class CleartextStorageConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
CleartextStorageConfiguration() { this = "ClearTextStorage" }
|
||||
|
||||
override predicate isSource(TaintSource src) {
|
||||
src instanceof SensitiveData::Source
|
||||
}
|
||||
|
||||
override predicate isSink(TaintSink sink) {
|
||||
sink instanceof ClearTextStorage::Sink
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
from CleartextStorageConfiguration config, TaintedPathSource source, TaintedPathSink sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getSink(), source, sink, "Sensitive data from $@ is stored here.",
|
||||
source.getSource(), source.getNode().(SensitiveData::Source).repr()
|
||||
@@ -0,0 +1,10 @@
|
||||
from flask import Flask, make_response, request
|
||||
|
||||
app = Flask("Leak password")
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
password = request.args.get("password")
|
||||
resp = make_response(render_template(...))
|
||||
resp.set_cookie("password", password)
|
||||
return resp
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
import semmle.python.web.HttpRequest
|
||||
|
||||
/**
|
||||
* Provides heuristics for identifying names related to sensitive information.
|
||||
@@ -142,7 +142,7 @@ module SensitiveData {
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "Call returning " + data.repr()
|
||||
result = "a call returning " + data.repr()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -166,6 +166,28 @@ module SensitiveData {
|
||||
|
||||
}
|
||||
|
||||
private class SensitiveRequestParameter extends SensitiveData::Source {
|
||||
|
||||
SensitiveData data;
|
||||
|
||||
SensitiveRequestParameter() {
|
||||
this.(CallNode).getFunction().(AttrNode).getName() = "get" and
|
||||
exists(string sensitive |
|
||||
this.(CallNode).getAnArg().refersTo(any(StringObject s | s.getText() = sensitive)) and
|
||||
data = HeuristicNames::getSensitiveDataForName(sensitive)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) {
|
||||
kind = data
|
||||
}
|
||||
|
||||
override string repr() {
|
||||
result = "a request parameter containing " + data.repr()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Backwards compatibility
|
||||
|
||||
Reference in New Issue
Block a user