@@ -9,6 +9,7 @@ private import codeql.ruby.DataFlow
9
9
private import codeql.ruby.TaintTracking:: TaintTracking
10
10
private import codeql.ruby.dataflow.RemoteFlowSources
11
11
private import SensitiveDataHeuristics:: HeuristicNames
12
+ private import SensitiveDataHeuristics
12
13
private import codeql.ruby.CFG
13
14
private import codeql.ruby.dataflow.SSA
14
15
@@ -39,6 +40,34 @@ module CleartextSources {
39
40
re .getConstantValue ( ) .getStringlikeValue ( ) = [ ".*" , ".+" ]
40
41
}
41
42
43
+ /** Holds if `c` is a sensitive data classification that is relevant to consider for Cleartext Storage queries. */
44
+ private predicate isRelevantClassification ( SensitiveDataClassification c ) {
45
+ c =
46
+ [
47
+ SensitiveDataClassification:: password ( ) , SensitiveDataClassification:: certificate ( ) ,
48
+ SensitiveDataClassification:: secret ( ) , SensitiveDataClassification:: private ( )
49
+ ]
50
+ }
51
+
52
+ pragma [ noinline]
53
+ private string getCombinedRelevantSensitiveRegexp ( ) {
54
+ // Combine all the maybe-sensitive regexps into one using non-capturing groups and |.
55
+ result =
56
+ "(?:" +
57
+ strictconcat ( string r , SensitiveDataClassification c |
58
+ r = maybeSensitiveRegexp ( c ) and isRelevantClassification ( c )
59
+ |
60
+ r , ")|(?:"
61
+ ) + ")"
62
+ }
63
+
64
+ /** Holds if the given name indicates the presence of sensitive data that is relevant to consider for Cleartext Storage queries. */
65
+ bindingset [ name]
66
+ private predicate nameIndicatesRelevantSensitiveData ( string name ) {
67
+ name .regexpMatch ( getCombinedRelevantSensitiveRegexp ( ) ) and
68
+ not name .regexpMatch ( notSensitiveRegexp ( ) )
69
+ }
70
+
42
71
/**
43
72
* Holds if `re` may be a regular expression that can be used to sanitize
44
73
* sensitive data with a call to `gsub`.
@@ -92,17 +121,17 @@ module CleartextSources {
92
121
}
93
122
94
123
/**
95
- * A call that might obfuscate a password , for example through hashing.
124
+ * A call that might obfuscate sensitive data , for example through hashing.
96
125
*/
97
126
private class ObfuscatorCall extends Sanitizer , DataFlow:: CallNode {
98
127
ObfuscatorCall ( ) { nameIsNotSensitive ( this .getMethodName ( ) ) }
99
128
}
100
129
101
130
/**
102
- * A data flow node that does not contain a clear-text password , according to its syntactic name.
131
+ * A data flow node that does not contain clear-text sensitive data , according to its syntactic name.
103
132
*/
104
- private class NameGuidedNonCleartextPassword extends NonCleartextPassword {
105
- NameGuidedNonCleartextPassword ( ) {
133
+ private class NameGuidedNonCleartextSensitive extends NonCleartextSensitive {
134
+ NameGuidedNonCleartextSensitive ( ) {
106
135
exists ( string name | nameIsNotSensitive ( name ) |
107
136
// accessing a non-sensitive variable
108
137
this .asExpr ( ) .getExpr ( ) .( VariableReadAccess ) .getVariable ( ) .getName ( ) = name
@@ -129,18 +158,23 @@ module CleartextSources {
129
158
}
130
159
131
160
/**
132
- * A data flow node that receives flow that is not a clear-text password .
161
+ * A data flow node that receives flow that is not clear-text sensitive data .
133
162
*/
134
- class NonCleartextPasswordFlow extends NonCleartextPassword {
135
- NonCleartextPasswordFlow ( ) {
136
- any ( NonCleartextPassword other ) .( DataFlow:: LocalSourceNode ) .flowsTo ( this )
163
+ class NonCleartextSensitiveFlow extends NonCleartextSensitive {
164
+ NonCleartextSensitiveFlow ( ) {
165
+ any ( NonCleartextSensitive other ) .( DataFlow:: LocalSourceNode ) .flowsTo ( this )
137
166
}
138
167
}
139
168
140
169
/**
141
- * A data flow node that does not contain a clear-text password.
170
+ * DEPRECATED: Use NonCleartextSensitiveFlow instead.
171
+ */
172
+ deprecated class NonCleartextPasswordFlow = NonCleartextSensitiveFlow ;
173
+
174
+ /**
175
+ * A data flow node that does not contain clear-text sensitive data.
142
176
*/
143
- abstract private class NonCleartextPassword extends DataFlow:: Node { }
177
+ abstract private class NonCleartextSensitive extends DataFlow:: Node { }
144
178
145
179
// `writeNode` assigns pair with key `name` to `val`
146
180
private predicate hashKeyWrite ( DataFlow:: CallNode writeNode , string name , DataFlow:: Node val ) {
@@ -153,18 +187,18 @@ module CleartextSources {
153
187
}
154
188
155
189
/**
156
- * A value written to a hash entry with a key that may contain password information.
190
+ * A value written to a hash entry with a key that may contain sensitive information.
157
191
*/
158
- private class HashKeyWritePasswordSource extends Source {
192
+ private class HashKeyWriteSensitiveSource extends Source {
159
193
private string name ;
160
194
private DataFlow:: ExprNode recv ;
161
195
162
- HashKeyWritePasswordSource ( ) {
196
+ HashKeyWriteSensitiveSource ( ) {
163
197
exists ( DataFlow:: CallNode writeNode |
164
- name . regexpMatch ( maybePassword ( ) ) and
198
+ nameIndicatesRelevantSensitiveData ( name ) and
165
199
not nameIsNotSensitive ( name ) and
166
200
// avoid safe values assigned to presumably unsafe names
167
- not this instanceof NonCleartextPassword and
201
+ not this instanceof NonCleartextSensitive and
168
202
// hash[name] = val
169
203
hashKeyWrite ( writeNode , name , this ) and
170
204
recv = writeNode .getReceiver ( )
@@ -177,7 +211,7 @@ module CleartextSources {
177
211
string getName ( ) { result = name }
178
212
179
213
/**
180
- * Gets the name of the hash variable that this password source is assigned
214
+ * Gets the name of the hash variable that this sensitive source is assigned
181
215
* to, if applicable.
182
216
*/
183
217
LocalVariable getVariable ( ) {
@@ -186,17 +220,17 @@ module CleartextSources {
186
220
}
187
221
188
222
/**
189
- * An entry into a hash literal that may contain a password
223
+ * An entry into a hash literal that may contain sensitive data
190
224
*/
191
- private class HashLiteralPasswordSource extends Source {
225
+ private class HashLiteralSensitiveSource extends Source {
192
226
private string name ;
193
227
194
- HashLiteralPasswordSource ( ) {
228
+ HashLiteralSensitiveSource ( ) {
195
229
exists ( CfgNodes:: ExprNodes:: HashLiteralCfgNode lit |
196
- name . regexpMatch ( maybePassword ( ) ) and
230
+ nameIndicatesRelevantSensitiveData ( name ) and
197
231
not nameIsNotSensitive ( name ) and
198
232
// avoid safe values assigned to presumably unsafe names
199
- not this instanceof NonCleartextPassword and
233
+ not this instanceof NonCleartextSensitive and
200
234
// hash = { name: val }
201
235
exists ( CfgNodes:: ExprNodes:: PairCfgNode p | p = lit .getAKeyValuePair ( ) |
202
236
p .getKey ( ) .getConstantValue ( ) .getStringlikeValue ( ) = name and
@@ -208,14 +242,14 @@ module CleartextSources {
208
242
override string describe ( ) { result = "a write to " + name }
209
243
}
210
244
211
- /** An assignment that may assign a password to a variable */
212
- private class AssignPasswordVariableSource extends Source {
245
+ /** An assignment that may assign sensitive data to a variable */
246
+ private class AssignSensitiveVariableSource extends Source {
213
247
string name ;
214
248
215
- AssignPasswordVariableSource ( ) {
249
+ AssignSensitiveVariableSource ( ) {
216
250
// avoid safe values assigned to presumably unsafe names
217
- not this instanceof NonCleartextPassword and
218
- name . regexpMatch ( maybePassword ( ) ) and
251
+ not this instanceof NonCleartextSensitive and
252
+ nameIndicatesRelevantSensitiveData ( name ) and
219
253
not nameIsNotSensitive ( name ) and
220
254
exists ( Assignment a |
221
255
this .asExpr ( ) .getExpr ( ) = a .getRightOperand ( ) and
@@ -226,14 +260,14 @@ module CleartextSources {
226
260
override string describe ( ) { result = "an assignment to " + name }
227
261
}
228
262
229
- /** A parameter that may contain a password . */
230
- private class ParameterPasswordSource extends Source {
263
+ /** A parameter that may contain sensitive data . */
264
+ private class ParameterSensitiveSource extends Source {
231
265
private string name ;
232
266
233
- ParameterPasswordSource ( ) {
234
- name . regexpMatch ( maybePassword ( ) ) and
267
+ ParameterSensitiveSource ( ) {
268
+ nameIndicatesRelevantSensitiveData ( name ) and
235
269
not nameIsNotSensitive ( name ) and
236
- not this instanceof NonCleartextPassword and
270
+ not this instanceof NonCleartextSensitive and
237
271
exists ( Parameter p , LocalVariable v |
238
272
v = p .getAVariable ( ) and
239
273
v .getName ( ) = name and
@@ -260,10 +294,10 @@ module CleartextSources {
260
294
deprecated predicate isAdditionalTaintStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
261
295
exists ( string name , ElementReference ref , LocalVariable hashVar |
262
296
// from `hsh[password] = "changeme"` to a `hsh[password]` read
263
- nodeFrom .( HashKeyWritePasswordSource ) .getName ( ) = name and
297
+ nodeFrom .( HashKeyWriteSensitiveSource ) .getName ( ) = name and
264
298
nodeTo .asExpr ( ) .getExpr ( ) = ref and
265
299
ref .getArgument ( 0 ) .getConstantValue ( ) .getStringlikeValue ( ) = name and
266
- nodeFrom .( HashKeyWritePasswordSource ) .getVariable ( ) = hashVar and
300
+ nodeFrom .( HashKeyWriteSensitiveSource ) .getVariable ( ) = hashVar and
267
301
ref .getReceiver ( ) .( VariableReadAccess ) .getVariable ( ) = hashVar and
268
302
nodeFrom .asExpr ( ) .getASuccessor * ( ) = nodeTo .asExpr ( )
269
303
)
0 commit comments