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

Skip to content

Commit b8a6f81

Browse files
committed
JS: Port CleartextLogging
1 parent a5c221f commit b8a6f81

4 files changed

Lines changed: 215 additions & 304 deletions

File tree

javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ module CleartextLogging {
1616
/** Gets a string that describes the type of this data flow source. */
1717
abstract string describe();
1818

19-
abstract DataFlow::FlowLabel getLabel();
19+
/**
20+
* DEPRECATED. Overriding this predicate no longer has any effect.
21+
*/
22+
deprecated DataFlow::FlowLabel getLabel() { result.isTaint() }
2023
}
2124

2225
/**
2326
* A data flow sink for clear-text logging of sensitive information.
2427
*/
2528
abstract class Sink extends DataFlow::Node {
26-
DataFlow::FlowLabel getLabel() { result.isTaint() }
29+
/**
30+
* DEPRECATED. Overriding this predicate no longer has any effect.
31+
*/
32+
deprecated DataFlow::FlowLabel getLabel() { result.isTaint() }
2733
}
2834

2935
/**
@@ -103,29 +109,28 @@ module CleartextLogging {
103109
abstract private class NonCleartextPassword extends DataFlow::Node { }
104110

105111
/**
106-
* An object with a property that may contain password information
107-
*
108-
* This is a source since `console.log(obj)` will show the properties of `obj`.
112+
* A value stored in a property that may contain password information
109113
*/
110114
private class ObjectPasswordPropertySource extends DataFlow::ValueNode, Source {
111115
string name;
112116

113117
ObjectPasswordPropertySource() {
114118
exists(DataFlow::PropWrite write |
119+
write.getPropertyName() = name and
115120
name.regexpMatch(maybePassword()) and
116121
not name.regexpMatch(notSensitiveRegexp()) and
117-
write = this.(DataFlow::SourceNode).getAPropertyWrite(name) and
122+
this = write.getRhs() and
118123
// avoid safe values assigned to presumably unsafe names
119-
not write.getRhs() instanceof NonCleartextPassword
124+
not this instanceof NonCleartextPassword
120125
)
121126
}
122127

123128
override string describe() { result = "an access to " + name }
124-
125-
override DataFlow::FlowLabel getLabel() { result.isTaint() }
126129
}
127130

128-
/** An access to a variable or property that might contain a password. */
131+
/**
132+
* An access to a variable or property that might contain a password.
133+
*/
129134
private class ReadPasswordSource extends DataFlow::ValueNode, Source {
130135
string name;
131136

@@ -147,8 +152,6 @@ module CleartextLogging {
147152
}
148153

149154
override string describe() { result = "an access to " + name }
150-
151-
override DataFlow::FlowLabel getLabel() { result.isTaint() }
152155
}
153156

154157
/** A call that might return a password. */
@@ -161,17 +164,35 @@ module CleartextLogging {
161164
}
162165

163166
override string describe() { result = "a call to " + name }
164-
165-
override DataFlow::FlowLabel getLabel() { result.isTaint() }
166167
}
167168

168169
/** An access to the sensitive object `process.env`. */
169170
class ProcessEnvSource extends Source {
170171
ProcessEnvSource() { this = NodeJSLib::process().getAPropertyRead("env") }
171172

172173
override string describe() { result = "process environment" }
174+
}
173175

174-
override DataFlow::FlowLabel getLabel() { result.isTaint() }
176+
/** Gets a data flow node referring to `process.env`. */
177+
private DataFlow::SourceNode processEnv(DataFlow::TypeTracker t) {
178+
t.start() and
179+
result instanceof ProcessEnvSource
180+
or
181+
exists(DataFlow::TypeTracker t2 | result = processEnv(t2).track(t2, t))
182+
}
183+
184+
/** Gets a data flow node referring to `process.env`. */
185+
DataFlow::SourceNode processEnv() { result = processEnv(DataFlow::TypeTracker::end()) }
186+
187+
/**
188+
* A property access on `process.env`, seen as a barrier.
189+
*/
190+
private class SafeEnvironmentVariableBarrier extends Barrier instanceof DataFlow::PropRead {
191+
SafeEnvironmentVariableBarrier() {
192+
this = processEnv().getAPropertyRead() and
193+
// If the name is known, it should not be sensitive
194+
not nameIndicatesSensitiveData(this.getPropertyName(), _)
195+
}
175196
}
176197

177198
/**
@@ -183,26 +204,10 @@ module CleartextLogging {
183204
succ.(DataFlow::PropRead).getBase() = pred
184205
}
185206

186-
private class PropReadAsBarrier extends Barrier {
187-
PropReadAsBarrier() {
188-
this = any(DataFlow::PropRead read).getBase() and
189-
// the 'foo' in 'foo.bar()' may have flow, we only want to suppress plain property reads
190-
not this = any(DataFlow::MethodCallNode call).getReceiver() and
191-
// do not block custom taint steps from this node
192-
not isAdditionalTaintStep(this, _)
193-
}
194-
}
195-
196207
/**
197208
* Holds if the edge `src` -> `trg` is an additional taint-step for clear-text logging of sensitive information.
198209
*/
199210
predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
200-
// A taint propagating data flow edge through objects: a tainted write taints the entire object.
201-
exists(DataFlow::PropWrite write |
202-
write.getRhs() = src and
203-
trg.(DataFlow::SourceNode).flowsTo(write.getBase())
204-
)
205-
or
206211
// A property-copy step,
207212
// dst[x] = src[x]
208213
// dst[x] = JSON.stringify(src[x])
@@ -218,7 +223,7 @@ module CleartextLogging {
218223
not exists(read.getPropertyName()) and
219224
not isFilteredPropertyName(read.getPropertyNameExpr().flow().getALocalSource()) and
220225
src = read.getBase() and
221-
trg = write.getBase().getALocalSource()
226+
trg = write.getBase().getPostUpdateNode()
222227
)
223228
or
224229
// Taint through the arguments object.

javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingQuery.qll

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,38 @@ private import CleartextLoggingCustomizations::CleartextLogging as CleartextLogg
2020
* added either by extending the relevant class, or by subclassing this configuration itself,
2121
* and amending the sources and sinks.
2222
*/
23-
class Configuration extends TaintTracking::Configuration {
23+
module CleartextLoggingConfig implements DataFlow::ConfigSig {
24+
predicate isSource(DataFlow::Node source) { source instanceof Source }
25+
26+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
27+
28+
predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
29+
30+
predicate isBarrierIn(DataFlow::Node node) {
31+
// We rely on heuristic sources, which tends to cause sources to overlap
32+
isSource(node)
33+
}
34+
35+
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) {
36+
CleartextLogging::isAdditionalTaintStep(src, trg)
37+
}
38+
39+
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet contents) {
40+
// Assume all properties of a logged object are themselves logged.
41+
contents = DataFlow::ContentSet::anyProperty() and
42+
isSink(node)
43+
}
44+
}
45+
46+
/**
47+
* Taint tracking flow for clear-text logging of sensitive information.
48+
*/
49+
module CleartextLoggingFlow = TaintTracking::Global<CleartextLoggingConfig>;
50+
51+
/**
52+
* DEPRECATED. Use the `CleartextLoggingFlow` module instead.
53+
*/
54+
deprecated class Configuration extends TaintTracking::Configuration {
2455
Configuration() { this = "CleartextLogging" }
2556

2657
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel lbl) {

javascript/ql/src/Security/CWE-312/CleartextLogging.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import javascript
1717
import semmle.javascript.security.dataflow.CleartextLoggingQuery
18-
import DataFlow::PathGraph
18+
import CleartextLoggingFlow::PathGraph
1919

2020
/**
2121
* Holds if `tl` is used in a browser environment.
@@ -33,9 +33,9 @@ predicate inBrowserEnvironment(TopLevel tl) {
3333
)
3434
}
3535

36-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
36+
from CleartextLoggingFlow::PathNode source, CleartextLoggingFlow::PathNode sink
3737
where
38-
cfg.hasFlowPath(source, sink) and
38+
CleartextLoggingFlow::flowPath(source, sink) and
3939
// ignore logging to the browser console (even though it is not a good practice)
4040
not inBrowserEnvironment(sink.getNode().asExpr().getTopLevel())
4141
select sink.getNode(), source, sink, "This logs sensitive data returned by $@ as clear text.",

0 commit comments

Comments
 (0)