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

Skip to content

Commit 15bb8b5

Browse files
committed
Python add new queries for clear-text logging and storage.
1 parent 79ebd56 commit 15bb8b5

6 files changed

Lines changed: 172 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<include src="CleartextStorage.qhelp" /></qhelp>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @name Clear-text logging of sensitive information
3+
* @description Logging sensitive information without encryption or hashing can
4+
* expose it to an attacker.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @precision high
8+
* @id py/clear-text-storage-of-sensitive-data
9+
* @tags security
10+
* external/cwe/cwe-312
11+
* external/cwe/cwe-315
12+
* external/cwe/cwe-359
13+
*/
14+
15+
import python
16+
import semmle.python.security.Paths
17+
18+
import semmle.python.security.TaintTracking
19+
import semmle.python.security.SensitiveData
20+
import semmle.python.security.ClearText
21+
22+
23+
class CleartextLoggingConfiguration extends TaintTracking::Configuration {
24+
25+
CleartextLoggingConfiguration() { this = "ClearTextLogging" }
26+
27+
override predicate isSource(TaintSource src) {
28+
src instanceof SensitiveData::Source
29+
}
30+
31+
override predicate isSink(TaintSink sink) {
32+
sink instanceof ClearTextLogging::Sink
33+
}
34+
35+
}
36+
37+
38+
from CleartextLoggingConfiguration config, TaintedPathSource source, TaintedPathSink sink
39+
where config.hasFlowPath(source, sink)
40+
select sink.getSink(), source, sink, "Sensitive data returned by $@ is stored here.",
41+
source.getSource(), source.getNode().(SensitiveData::Source).repr()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
Sensitive information that is stored unencrypted is accessible to an attacker
9+
who gains access to the storage. This is particularly important for cookies,
10+
which are stored on the machine of the end-user.
11+
</p>
12+
</overview>
13+
14+
<recommendation>
15+
<p>
16+
Ensure that sensitive information is always encrypted before being stored.
17+
If possible, avoid placing sensitive information in cookies altogether.
18+
Instead, prefer storing, in the cookie, a key that can be used to look up the
19+
sensitive information.
20+
</p>
21+
<p>
22+
In general, decrypt sensitive information only at the point where it is
23+
necessary for it to be used in cleartext.
24+
</p>
25+
26+
<p>
27+
28+
Be aware that external processes often store the <code>standard
29+
out</code> and <code>standard error</code> streams of the application,
30+
causing logged sensitive information to be stored as well.
31+
32+
</p>
33+
34+
</recommendation>
35+
36+
<example>
37+
<p>
38+
The following example code stores user credentials (in this case, their password) in a cookie in plain text:
39+
</p>
40+
<sample src="examples/password_in_cookie.py"/>
41+
<p>
42+
Instead, the credentials should be encrypted, for instance by using the <code>cryptography</code> module, or not stored at all.
43+
44+
</example>
45+
46+
<references>
47+
48+
<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>
49+
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
50+
51+
</references>
52+
</qhelp>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @name Clear-text storage of sensitive information
3+
* @description Sensitive information stored without encryption or hashing can expose it to an
4+
* attacker.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @precision high
8+
* @id py/clear-text-logging
9+
* @tags security
10+
* external/cwe/cwe-312
11+
* external/cwe/cwe-315
12+
* external/cwe/cwe-359
13+
*/
14+
15+
import python
16+
import semmle.python.security.Paths
17+
18+
import semmle.python.security.TaintTracking
19+
import semmle.python.security.SensitiveData
20+
import semmle.python.security.ClearText
21+
22+
class CleartextStorageConfiguration extends TaintTracking::Configuration {
23+
24+
CleartextStorageConfiguration() { this = "ClearTextStorage" }
25+
26+
override predicate isSource(TaintSource src) {
27+
src instanceof SensitiveData::Source
28+
}
29+
30+
override predicate isSink(TaintSink sink) {
31+
sink instanceof ClearTextStorage::Sink
32+
}
33+
34+
}
35+
36+
37+
from CleartextStorageConfiguration config, TaintedPathSource source, TaintedPathSink sink
38+
where config.hasFlowPath(source, sink)
39+
select sink.getSink(), source, sink, "Sensitive data from $@ is stored here.",
40+
source.getSource(), source.getNode().(SensitiveData::Source).repr()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from flask import Flask, make_response, request
2+
3+
app = Flask("Leak password")
4+
5+
@app.route('/')
6+
def index():
7+
password = request.args.get("password")
8+
resp = make_response(render_template(...))
9+
resp.set_cookie("password", password)
10+
return resp

python/ql/src/semmle/python/security/SensitiveData.qll

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import python
1313
import semmle.python.security.TaintTracking
14-
14+
import semmle.python.web.HttpRequest
1515

1616
/**
1717
* Provides heuristics for identifying names related to sensitive information.
@@ -142,7 +142,7 @@ module SensitiveData {
142142
}
143143

144144
override string repr() {
145-
result = "Call returning " + data.repr()
145+
result = "a call returning " + data.repr()
146146
}
147147

148148
}
@@ -166,6 +166,28 @@ module SensitiveData {
166166

167167
}
168168

169+
private class SensitiveRequestParameter extends SensitiveData::Source {
170+
171+
SensitiveData data;
172+
173+
SensitiveRequestParameter() {
174+
this.(CallNode).getFunction().(AttrNode).getName() = "get" and
175+
exists(string sensitive |
176+
this.(CallNode).getAnArg().refersTo(any(StringObject s | s.getText() = sensitive)) and
177+
data = HeuristicNames::getSensitiveDataForName(sensitive)
178+
)
179+
}
180+
181+
override predicate isSourceOf(TaintKind kind) {
182+
kind = data
183+
}
184+
185+
override string repr() {
186+
result = "a request parameter containing " + data.repr()
187+
}
188+
189+
}
190+
169191
}
170192

171193
//Backwards compatibility

0 commit comments

Comments
 (0)