@@ -17,31 +17,56 @@ import javascript
1717 * INTERNAL: Do not use directly.
1818 */
1919module HeuristicNames {
20- /** Gets a regular expression that identifies strings that look like they represent secret data that are not passwords. */
21- string suspiciousNonPassword ( ) { result = "(?is).*(secret|account|accnt|(?<!un)trusted).*" }
20+ /**
21+ * Gets a regular expression that identifies strings that may indicate the presence of secret
22+ * or trusted data.
23+ */
24+ string maybeSecret ( ) { result = "(?is).*((?<!is)secret|(?<!un|is)trusted).*" }
2225
23- /** Gets a regular expression that identifies strings that look like they represent secret data that are passwords. */
24- string suspiciousPassword ( ) { result = "(?is).*(password|passwd).*" }
26+ /**
27+ * Gets a regular expression that identifies strings that may indicate the presence of
28+ * user names or other account information.
29+ */
30+ string maybeAccountInfo ( ) {
31+ result = "(?is).*acc(ou)?nt.*" or
32+ result = "(?is).*(puid|username|userid).*"
33+ }
2534
26- /** Gets a regular expression that identifies strings that look like they represent secret data. */
27- string suspicious ( ) { result = suspiciousPassword ( ) or result = suspiciousNonPassword ( ) }
35+ /**
36+ * Gets a regular expression that identifies strings that may indicate the presence of
37+ * a password or an authorization key.
38+ */
39+ string maybePassword ( ) {
40+ result = "(?is).*pass(wd|word|code|phrase)(?!.*question).*" or
41+ result = "(?is).*(auth(entication|ori[sz]ation)?)key.*"
42+ }
2843
2944 /**
30- * Gets a regular expression that identifies strings that look like they represent data that is
31- * hashed or encrypted .
45+ * Gets a regular expression that identifies strings that may indicate the presence of
46+ * a certificate .
3247 */
33- string nonSuspicious ( ) {
34- result = "(?is).*(redact|censor|obfuscate|hash|md5|sha|((?<!un)(en))?(crypt|code)).*"
48+ string maybeCertificate ( ) { result = "(?is).*(cert)(?!.*(format|name)).*" }
49+
50+ /**
51+ * Gets a regular expression that identifies strings that may indicate the presence
52+ * of sensitive data, with `classification` describing the kind of sensitive data involved.
53+ */
54+ string maybeSensitive ( SensitiveExpr:: Classification classification ) {
55+ result = maybeSecret ( ) and classification = SensitiveExpr:: secret ( )
56+ or
57+ result = maybeAccountInfo ( ) and classification = SensitiveExpr:: id ( )
58+ or
59+ result = maybePassword ( ) and classification = SensitiveExpr:: password ( )
60+ or
61+ result = maybeCertificate ( ) and classification = SensitiveExpr:: certificate ( )
3562 }
3663
3764 /**
38- * Gets a regular expression that identifies names that look like they represent credential information.
65+ * Gets a regular expression that identifies strings that may indicate the presence of data
66+ * that is hashed or encrypted, and hence rendered non-sensitive.
3967 */
40- string suspiciousCredentials ( ) {
41- result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
42- result = "(?i).*(puid|username|userid).*" or
43- result = "(?i).*(cert)(?!.*(format|name)).*" or
44- result = "(?i).*(auth(entication|ori[sz]ation)?)key.*"
68+ string notSensitive ( ) {
69+ result = "(?is).*(redact|censor|obfuscate|hash|md5|sha|((?<!un)(en))?(crypt|code)).*"
4570 }
4671}
4772private import HeuristicNames
@@ -50,22 +75,60 @@ private import HeuristicNames
5075abstract class SensitiveExpr extends Expr {
5176 /** Gets a human-readable description of this expression for use in alert messages. */
5277 abstract string describe ( ) ;
78+
79+ /** Gets a classification of the kind of sensitive data this expression might contain. */
80+ abstract SensitiveExpr:: Classification getClassification ( ) ;
81+ }
82+
83+ module SensitiveExpr {
84+ /**
85+ * A classification of different kinds of sensitive data:
86+ *
87+ * - secret: generic secret or trusted data;
88+ * - id: a user name or other account information;
89+ * - password: a password or authorization key;
90+ * - certificate: a certificate.
91+ *
92+ * While classifications are represented as strings, this should not be relied upon.
93+ * Instead, use the predicates below to work with classifications.
94+ */
95+ class Classification extends string {
96+ Classification ( ) {
97+ this = "secret" or this = "id" or this = "password" or this = "certificate"
98+ }
99+ }
100+
101+ /** Gets the classification for secret or trusted data. */
102+ Classification secret ( ) { result = "secret" }
103+
104+ /** Gets the classification for user names or other account information. */
105+ Classification id ( ) { result = "id" }
106+
107+ /** Gets the classification for passwords or authorization keys. */
108+ Classification password ( ) { result = "password" }
109+
110+ /** Gets the classification for certificates. */
111+ Classification certificate ( ) { result = "certificate" }
53112}
54113
55114/** A function call that might produce sensitive data. */
56115class SensitiveCall extends SensitiveExpr , InvokeExpr {
116+ SensitiveExpr:: Classification classification ;
117+
57118 SensitiveCall ( ) {
58- this .getCalleeName ( ) instanceof SensitiveDataFunctionName
119+ classification = this .getCalleeName ( ) . ( SensitiveDataFunctionName ) . getClassification ( )
59120 or
60121 // This is particularly to pick up methods with an argument like "password", which
61122 // may indicate a lookup.
62123 exists ( string s | this .getAnArgument ( ) .mayHaveStringValue ( s ) |
63- s .regexpMatch ( suspicious ( ) ) and
64- not s .regexpMatch ( nonSuspicious ( ) )
124+ s .regexpMatch ( maybeSensitive ( classification ) ) and
125+ not s .regexpMatch ( notSensitive ( ) )
65126 )
66127 }
67128
68129 override string describe ( ) { result = "a call to " + getCalleeName ( ) }
130+
131+ override SensitiveExpr:: Classification getClassification ( ) { result = classification }
69132}
70133
71134/** An access to a variable or property that might contain sensitive data. */
@@ -85,14 +148,17 @@ abstract class SensitiveVariableAccess extends SensitiveExpr {
85148}
86149
87150/** A write to a location that might contain sensitive data. */
88- abstract class SensitiveWrite extends DataFlow:: Node { }
151+ abstract class SensitiveWrite extends DataFlow:: Node {
152+ }
89153
90154/** A write to a variable or property that might contain sensitive data. */
91155private class BasicSensitiveWrite extends SensitiveWrite {
156+ SensitiveExpr:: Classification classification ;
157+
92158 BasicSensitiveWrite ( ) {
93159 exists ( string name |
94- name .regexpMatch ( suspicious ( ) ) and
95- not name .regexpMatch ( nonSuspicious ( ) )
160+ name .regexpMatch ( maybeSensitive ( classification ) ) and
161+ not name .regexpMatch ( notSensitive ( ) )
96162 |
97163 exists ( DataFlow:: PropWrite pwn |
98164 pwn .getPropertyName ( ) = name and
@@ -110,13 +176,20 @@ private class BasicSensitiveWrite extends SensitiveWrite {
110176 )
111177 )
112178 }
179+
180+ /** Gets a classification of the kind of sensitive data the write might handle. */
181+ SensitiveExpr:: Classification getClassification ( ) { result = classification }
113182}
114183
115184/** An access to a variable or property that might contain sensitive data. */
116185private class BasicSensitiveVariableAccess extends SensitiveVariableAccess {
186+ SensitiveExpr:: Classification classification ;
187+
117188 BasicSensitiveVariableAccess ( ) {
118- name .regexpMatch ( suspicious ( ) ) and not name .regexpMatch ( nonSuspicious ( ) )
189+ name .regexpMatch ( maybeSensitive ( classification ) ) and not name .regexpMatch ( notSensitive ( ) )
119190 }
191+
192+ override SensitiveExpr:: Classification getClassification ( ) { result = classification }
120193}
121194
122195/** A function name that suggests it may be sensitive. */
@@ -129,11 +202,18 @@ abstract class SensitiveFunctionName extends string {
129202}
130203
131204/** A function name that suggests it may produce sensitive data. */
132- abstract class SensitiveDataFunctionName extends SensitiveFunctionName { }
205+ abstract class SensitiveDataFunctionName extends SensitiveFunctionName {
206+ /** Gets a classification of the kind of sensitive data this function may produce. */
207+ abstract SensitiveExpr:: Classification getClassification ( ) ;
208+ }
133209
134210/** A method that might return sensitive data, based on the name. */
135211class CredentialsFunctionName extends SensitiveDataFunctionName {
136- CredentialsFunctionName ( ) { this .regexpMatch ( suspicious ( ) ) }
212+ SensitiveExpr:: Classification classification ;
213+
214+ CredentialsFunctionName ( ) { this .regexpMatch ( maybeSensitive ( classification ) ) }
215+
216+ override SensitiveExpr:: Classification getClassification ( ) { result = classification }
137217}
138218
139219/**
@@ -163,41 +243,10 @@ class ProtectCall extends DataFlow::CallNode {
163243 }
164244}
165245
166- /**
167- * Classes for expressions containing cleartext passwords.
168- */
169- private module CleartextPasswords {
170- bindingset [ name]
171- private predicate isCleartextPasswordIndicator ( string name ) {
172- name .regexpMatch ( suspiciousPassword ( ) ) and
173- not name .regexpMatch ( nonSuspicious ( ) )
174- }
175-
176- /** An expression that might contain a cleartext password. */
177- abstract class CleartextPasswordExpr extends SensitiveExpr { }
178-
179- /** A function name that suggests it may produce a cleartext password. */
180- private class CleartextPasswordDataFunctionName extends SensitiveDataFunctionName {
181- CleartextPasswordDataFunctionName ( ) { isCleartextPasswordIndicator ( this ) }
182- }
246+ /** An expression that might contain a clear-text password. */
247+ class CleartextPasswordExpr extends SensitiveExpr {
248+ CleartextPasswordExpr ( ) { this .( SensitiveExpr ) .getClassification ( ) = SensitiveExpr:: password ( ) }
183249
184- /** A call that might return a cleartext password. */
185- private class CleartextPasswordCallExpr extends CleartextPasswordExpr , SensitiveCall {
186- CleartextPasswordCallExpr ( ) {
187- this .getCalleeName ( ) instanceof CleartextPasswordDataFunctionName
188- or
189- // This is particularly to pick up methods with an argument like "password", which
190- // may indicate a lookup.
191- exists ( string s |
192- this .getAnArgument ( ) .mayHaveStringValue ( s ) and
193- isCleartextPasswordIndicator ( s )
194- )
195- }
196- }
197-
198- /** An access to a variable or property that might contain a cleartext password. */
199- private class CleartextPasswordLookupExpr extends CleartextPasswordExpr , SensitiveVariableAccess {
200- CleartextPasswordLookupExpr ( ) { isCleartextPasswordIndicator ( name ) }
201- }
250+ override string describe ( ) { none ( ) }
251+ override SensitiveExpr:: Classification getClassification ( ) { none ( ) }
202252}
203- import CleartextPasswords
0 commit comments