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

Skip to content

Commit dd07417

Browse files
committed
Python: Move WeakSensitiveDataHashing to new dataflow API
I adopted helper predicates to do the "heavy" lifting of .asPathNode1(), maybe I like this approach better... let me know what you think 😊
1 parent 9d6b96d commit dd07417

3 files changed

Lines changed: 91 additions & 31 deletions

File tree

python/ql/lib/semmle/python/security/dataflow/WeakSensitiveDataHashingQuery.qll

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ module NormalHashFunction {
2424
import WeakSensitiveDataHashingCustomizations::NormalHashFunction
2525

2626
/**
27+
* DEPRECATED: Use `Flow` module instead.
28+
*
2729
* A taint-tracking configuration for detecting use of a broken or weak
2830
* cryptographic hashing algorithm on sensitive data.
2931
*/
30-
class Configuration extends TaintTracking::Configuration {
32+
deprecated class Configuration extends TaintTracking::Configuration {
3133
Configuration() { this = "NormalHashFunction" }
3234

3335
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -44,6 +46,21 @@ module NormalHashFunction {
4446
sensitiveDataExtraStepForCalls(node1, node2)
4547
}
4648
}
49+
50+
private module Config implements DataFlow::ConfigSig {
51+
predicate isSource(DataFlow::Node source) { source instanceof Source }
52+
53+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
54+
55+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
56+
57+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
58+
sensitiveDataExtraStepForCalls(node1, node2)
59+
}
60+
}
61+
62+
/** Global taint-tracking for detecting "use of a broken or weak cryptographic hashing algorithm on sensitive data" vulnerabilities. */
63+
module Flow = TaintTracking::Global<Config>;
4764
}
4865

4966
/**
@@ -57,13 +74,15 @@ module ComputationallyExpensiveHashFunction {
5774
import WeakSensitiveDataHashingCustomizations::ComputationallyExpensiveHashFunction
5875

5976
/**
77+
* DEPRECATED: Use `Flow` module instead.
78+
*
6079
* A taint-tracking configuration for detecting use of a broken or weak
6180
* cryptographic hashing algorithm on passwords.
6281
*
6382
* Passwords has stricter requirements on the hashing algorithm used (must be
6483
* computationally expensive to prevent brute-force attacks).
6584
*/
66-
class Configuration extends TaintTracking::Configuration {
85+
deprecated class Configuration extends TaintTracking::Configuration {
6786
Configuration() { this = "ComputationallyExpensiveHashFunction" }
6887

6988
override predicate isSource(DataFlow::Node source) { source instanceof Source }
@@ -80,4 +99,49 @@ module ComputationallyExpensiveHashFunction {
8099
sensitiveDataExtraStepForCalls(node1, node2)
81100
}
82101
}
102+
103+
/**
104+
* Passwords has stricter requirements on the hashing algorithm used (must be
105+
* computationally expensive to prevent brute-force attacks).
106+
*/
107+
private module Config implements DataFlow::ConfigSig {
108+
predicate isSource(DataFlow::Node source) { source instanceof Source }
109+
110+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
111+
112+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
113+
114+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
115+
sensitiveDataExtraStepForCalls(node1, node2)
116+
}
117+
}
118+
119+
/** Global taint-tracking for detecting "use of a broken or weak cryptographic hashing algorithm on passwords" vulnerabilities. */
120+
module Flow = TaintTracking::Global<Config>;
121+
}
122+
123+
/**
124+
* Global taint-tracking for detecting both variants of "use of a broken or weak
125+
* cryptographic hashing algorithm on sensitive data" vulnerabilities.
126+
*
127+
* See convenience predicates `normalHashFunctionFlowPath` and
128+
* `computationallyExpensiveHashFunctionFlowPath`.
129+
*/
130+
module WeakSensitiveDataHashingFlow =
131+
DataFlow::MergePathGraph<NormalHashFunction::Flow::PathNode,
132+
ComputationallyExpensiveHashFunction::Flow::PathNode, NormalHashFunction::Flow::PathGraph,
133+
ComputationallyExpensiveHashFunction::Flow::PathGraph>;
134+
135+
/** Holds if data can flow from `source` to `sink` with `NormalHashFunction::Flow`. */
136+
predicate normalHashFunctionFlowPath(
137+
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink
138+
) {
139+
NormalHashFunction::Flow::flowPath(source.asPathNode1(), sink.asPathNode1())
140+
}
141+
142+
/** Holds if data can flow from `source` to `sink` with `ComputationallyExpensiveHashFunction::Flow`. */
143+
predicate computationallyExpensiveHashFunctionFlowPath(
144+
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink
145+
) {
146+
ComputationallyExpensiveHashFunction::Flow::flowPath(source.asPathNode2(), sink.asPathNode2())
83147
}

python/ql/src/Security/CWE-327/WeakSensitiveDataHashing.ql

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,29 @@ import python
1616
import semmle.python.security.dataflow.WeakSensitiveDataHashingQuery
1717
import semmle.python.dataflow.new.DataFlow
1818
import semmle.python.dataflow.new.TaintTracking
19-
import DataFlow::PathGraph
19+
import WeakSensitiveDataHashingFlow::PathGraph
2020

2121
from
22-
DataFlow::PathNode source, DataFlow::PathNode sink, string ending, string algorithmName,
23-
string classification
22+
WeakSensitiveDataHashingFlow::PathNode source, WeakSensitiveDataHashingFlow::PathNode sink,
23+
string ending, string algorithmName, string classification
2424
where
25-
exists(NormalHashFunction::Configuration config |
26-
config.hasFlowPath(source, sink) and
27-
algorithmName = sink.getNode().(NormalHashFunction::Sink).getAlgorithmName() and
28-
classification = source.getNode().(NormalHashFunction::Source).getClassification() and
29-
ending = "."
30-
)
25+
normalHashFunctionFlowPath(source, sink) and
26+
algorithmName = sink.getNode().(NormalHashFunction::Sink).getAlgorithmName() and
27+
classification = source.getNode().(NormalHashFunction::Source).getClassification() and
28+
ending = "."
3129
or
32-
exists(ComputationallyExpensiveHashFunction::Configuration config |
33-
config.hasFlowPath(source, sink) and
34-
algorithmName = sink.getNode().(ComputationallyExpensiveHashFunction::Sink).getAlgorithmName() and
35-
classification =
36-
source.getNode().(ComputationallyExpensiveHashFunction::Source).getClassification() and
37-
(
38-
sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
39-
ending = "."
40-
or
41-
not sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
42-
ending =
43-
" for " + classification +
44-
" hashing, since it is not a computationally expensive hash function."
45-
)
30+
computationallyExpensiveHashFunctionFlowPath(source, sink) and
31+
algorithmName = sink.getNode().(ComputationallyExpensiveHashFunction::Sink).getAlgorithmName() and
32+
classification =
33+
source.getNode().(ComputationallyExpensiveHashFunction::Source).getClassification() and
34+
(
35+
sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
36+
ending = "."
37+
or
38+
not sink.getNode().(ComputationallyExpensiveHashFunction::Sink).isComputationallyExpensive() and
39+
ending =
40+
" for " + classification +
41+
" hashing, since it is not a computationally expensive hash function."
4642
)
4743
select sink.getNode(), source, sink,
4844
"$@ is used in a hashing algorithm (" + algorithmName + ") that is insecure" + ending,

python/ql/test/query-tests/Security/CWE-327-WeakSensitiveDataHashing/WeakSensitiveDataHashing.expected

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ edges
55
| test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:2:37:2:51 | GSSA Variable get_certificate |
66
| test_cryptodome.py:2:37:2:51 | GSSA Variable get_certificate | test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate |
77
| test_cryptodome.py:6:5:6:13 | SSA variable dangerous | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous |
8-
| test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate | test_cryptodome.py:6:5:6:13 | SSA variable dangerous |
8+
| test_cryptodome.py:6:17:6:31 | ControlFlowNode for get_certificate | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() |
99
| test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:6:5:6:13 | SSA variable dangerous |
1010
| test_cryptodome.py:13:5:13:13 | SSA variable dangerous | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous |
11-
| test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | test_cryptodome.py:13:5:13:13 | SSA variable dangerous |
11+
| test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() |
1212
| test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:13:5:13:13 | SSA variable dangerous |
1313
| test_cryptodome.py:20:5:20:13 | SSA variable dangerous | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous |
14-
| test_cryptodome.py:20:17:20:28 | ControlFlowNode for get_password | test_cryptodome.py:20:5:20:13 | SSA variable dangerous |
14+
| test_cryptodome.py:20:17:20:28 | ControlFlowNode for get_password | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() |
1515
| test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:20:5:20:13 | SSA variable dangerous |
1616
| test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:3:23:3:34 | GSSA Variable get_password |
1717
| test_cryptography.py:3:23:3:34 | GSSA Variable get_password | test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password |
1818
| test_cryptography.py:3:23:3:34 | GSSA Variable get_password | test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password |
1919
| test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:3:37:3:51 | GSSA Variable get_certificate |
2020
| test_cryptography.py:3:37:3:51 | GSSA Variable get_certificate | test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate |
2121
| test_cryptography.py:7:5:7:13 | SSA variable dangerous | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous |
22-
| test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate | test_cryptography.py:7:5:7:13 | SSA variable dangerous |
22+
| test_cryptography.py:7:17:7:31 | ControlFlowNode for get_certificate | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() |
2323
| test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:7:5:7:13 | SSA variable dangerous |
2424
| test_cryptography.py:15:5:15:13 | SSA variable dangerous | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous |
25-
| test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password | test_cryptography.py:15:5:15:13 | SSA variable dangerous |
25+
| test_cryptography.py:15:17:15:28 | ControlFlowNode for get_password | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() |
2626
| test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:15:5:15:13 | SSA variable dangerous |
2727
| test_cryptography.py:23:5:23:13 | SSA variable dangerous | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous |
28-
| test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password | test_cryptography.py:23:5:23:13 | SSA variable dangerous |
28+
| test_cryptography.py:23:17:23:28 | ControlFlowNode for get_password | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() |
2929
| test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:23:5:23:13 | SSA variable dangerous |
3030
nodes
3131
| test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember |

0 commit comments

Comments
 (0)