@@ -7,140 +7,140 @@ import java
7
7
import semmle.code.java.dataflow.FlowSources
8
8
import semmle.code.java.dataflow.TaintTracking
9
9
10
- module ExternalAPIs {
11
- /**
12
- * A `Method` that is considered a "safe" external API from a security perspective.
13
- */
14
- abstract class SafeExternalAPIMethod extends Method { }
15
-
16
- /** The default set of "safe" external APIs. */
17
- class DefaultSafeExternalAPIMethod extends SafeExternalAPIMethod {
18
- DefaultSafeExternalAPIMethod ( ) {
19
- this instanceof EqualsMethod
20
- or
21
- getName ( ) .regexpMatch ( "size|length|compareTo|getClass|lastIndexOf" )
22
- or
23
- this .getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "Validate" )
24
- or
25
- getQualifiedName ( ) = "Objects.equals"
26
- or
27
- getDeclaringType ( ) instanceof TypeString and getName ( ) = "equals"
28
- or
29
- getDeclaringType ( ) .hasQualifiedName ( "com.google.common.base" , "Preconditions" )
30
- or
31
- getDeclaringType ( ) .getPackage ( ) .getName ( ) .matches ( "org.junit%" )
32
- or
33
- getDeclaringType ( ) .hasQualifiedName ( "com.google.common.base" , "Strings" ) and
34
- getName ( ) = "isNullOrEmpty"
35
- or
36
- getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "StringUtils" ) and
37
- getName ( ) = "isNotEmpty"
38
- or
39
- getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "Character" ) and
40
- getName ( ) = "isDigit"
41
- or
42
- getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "String" ) and
43
- getName ( ) .regexpMatch ( "equalsIgnoreCase|regionMatches" )
44
- or
45
- getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "Boolean" ) and
46
- getName ( ) = "parseBoolean"
47
- or
48
- getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.io" , "IOUtils" ) and
49
- getName ( ) = "closeQuietly"
10
+ /**
11
+ * A `Method` that is considered a "safe" external API from a security perspective.
12
+ */
13
+ abstract class SafeExternalAPIMethod extends Method { }
14
+
15
+ /** The default set of "safe" external APIs. */
16
+ private class DefaultSafeExternalAPIMethod extends SafeExternalAPIMethod {
17
+ DefaultSafeExternalAPIMethod ( ) {
18
+ this instanceof EqualsMethod
19
+ or
20
+ getName ( ) .regexpMatch ( "size|length|compareTo|getClass|lastIndexOf" )
21
+ or
22
+ this .getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "Validate" )
23
+ or
24
+ getQualifiedName ( ) = "Objects.equals"
25
+ or
26
+ getDeclaringType ( ) instanceof TypeString and getName ( ) = "equals"
27
+ or
28
+ getDeclaringType ( ) .hasQualifiedName ( "com.google.common.base" , "Preconditions" )
29
+ or
30
+ getDeclaringType ( ) .getPackage ( ) .getName ( ) .matches ( "org.junit%" )
31
+ or
32
+ getDeclaringType ( ) .hasQualifiedName ( "com.google.common.base" , "Strings" ) and
33
+ getName ( ) = "isNullOrEmpty"
34
+ or
35
+ getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "StringUtils" ) and
36
+ getName ( ) = "isNotEmpty"
37
+ or
38
+ getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "Character" ) and
39
+ getName ( ) = "isDigit"
40
+ or
41
+ getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "String" ) and
42
+ getName ( ) .regexpMatch ( "equalsIgnoreCase|regionMatches" )
43
+ or
44
+ getDeclaringType ( ) .hasQualifiedName ( "java.lang" , "Boolean" ) and
45
+ getName ( ) = "parseBoolean"
46
+ or
47
+ getDeclaringType ( ) .hasQualifiedName ( "org.apache.commons.io" , "IOUtils" ) and
48
+ getName ( ) = "closeQuietly"
49
+ or
50
+ getDeclaringType ( ) .hasQualifiedName ( "org.springframework.util" , "StringUtils" ) and
51
+ getName ( ) .regexpMatch ( "hasText|isEmpty" )
52
+ }
53
+ }
54
+
55
+ /** A node representing data being passed to an external API. */
56
+ class ExternalAPIDataNode extends DataFlow:: Node {
57
+ Call call ;
58
+ int i ;
59
+
60
+ ExternalAPIDataNode ( ) {
61
+ (
62
+ // Argument to call to a method
63
+ this .asExpr ( ) = call .getArgument ( i )
50
64
or
51
- getDeclaringType ( ) .hasQualifiedName ( "org.springframework.util" , "StringUtils" ) and
52
- getName ( ) .regexpMatch ( "hasText|isEmpty" )
53
- }
65
+ // Qualifier to call to a method which returns non trivial value
66
+ this .asExpr ( ) = call .getQualifier ( ) and
67
+ i = - 1 and
68
+ not call .getCallee ( ) .getReturnType ( ) instanceof VoidType and
69
+ not call .getCallee ( ) .getReturnType ( ) instanceof BooleanType
70
+ ) and
71
+ // Defined outside the source archive
72
+ not call .getCallee ( ) .fromSource ( ) and
73
+ // Not a call to an method which is overridden in source
74
+ not exists ( Method m |
75
+ m .getASourceOverriddenMethod ( ) = call .getCallee ( ) .getSourceDeclaration ( ) and
76
+ m .fromSource ( )
77
+ ) and
78
+ // Not already modeled as a taint step
79
+ not exists ( DataFlow:: Node next | TaintTracking:: localTaintStep ( this , next ) ) and
80
+ // Not a call to a known safe external API
81
+ not call .getCallee ( ) instanceof SafeExternalAPIMethod
54
82
}
55
83
56
- /** A node representing data being passed to an external API. */
57
- class ExternalAPIDataNode extends DataFlow:: Node {
58
- Call call ;
59
- int i ;
60
-
61
- ExternalAPIDataNode ( ) {
62
- (
63
- // Argument to call to a method
64
- this .asExpr ( ) = call .getArgument ( i )
65
- or
66
- // Qualifier to call to a method which returns non trivial value
67
- this .asExpr ( ) = call .getQualifier ( ) and
68
- i = - 1 and
69
- not call .getCallee ( ) .getReturnType ( ) instanceof VoidType and
70
- not call .getCallee ( ) .getReturnType ( ) instanceof BooleanType
71
- ) and
72
- // Defined outside the source archive
73
- not call .getCallee ( ) .fromSource ( ) and
74
- // Not a call to an method which is overridden in source
75
- not exists ( Method m |
76
- m .getASourceOverriddenMethod ( ) = call .getCallee ( ) .getSourceDeclaration ( ) and
77
- m .fromSource ( )
78
- ) and
79
- // Not already modeled as a taint step
80
- not exists ( DataFlow:: Node next | TaintTracking:: localTaintStep ( this , next ) ) and
81
- // Not a call to a known safe external API
82
- not call .getCallee ( ) instanceof SafeExternalAPIMethod
83
- }
84
-
85
- /** Gets the called API `Method`. */
86
- Method getMethod ( ) { result = call .getCallee ( ) }
87
-
88
- /** Gets the index which is passed untrusted data (where -1 indicates the qualifier). */
89
- int getIndex ( ) { result = i }
90
-
91
- /** Gets the description of the method being called. */
92
- string getMethodDescription ( ) {
93
- result =
94
- getMethod ( ) .getDeclaringType ( ) .getPackage ( ) + "." + getMethod ( ) .getQualifiedName ( )
95
- }
84
+ /** Gets the called API `Method`. */
85
+ Method getMethod ( ) { result = call .getCallee ( ) }
86
+
87
+ /** Gets the index which is passed untrusted data (where -1 indicates the qualifier). */
88
+ int getIndex ( ) { result = i }
89
+
90
+ /** Gets the description of the method being called. */
91
+ string getMethodDescription ( ) {
92
+ result = getMethod ( ) .getDeclaringType ( ) .getPackage ( ) + "." + getMethod ( ) .getQualifiedName ( )
96
93
}
94
+ }
97
95
98
- class UntrustedDataToExternalAPIConfig extends TaintTracking:: Configuration {
99
- UntrustedDataToExternalAPIConfig ( ) { this = "UntrustedDataToExternalAPIConfig" }
96
+ /** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
97
+ class UntrustedDataToExternalAPIConfig extends TaintTracking:: Configuration {
98
+ UntrustedDataToExternalAPIConfig ( ) { this = "UntrustedDataToExternalAPIConfig" }
100
99
101
- override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
100
+ override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
102
101
103
- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof ExternalAPIDataNode }
102
+ override predicate isSink ( DataFlow:: Node sink ) { sink instanceof ExternalAPIDataNode }
103
+ }
104
+
105
+ /** A node representing untrusted data being passed to an external API. */
106
+ class UntrustedExternalAPIDataNode extends ExternalAPIDataNode {
107
+ UntrustedExternalAPIDataNode ( ) { any ( UntrustedDataToExternalAPIConfig c ) .hasFlow ( _, this ) }
108
+
109
+ /** Gets a source of untrusted data which is passed to this external API data node. */
110
+ DataFlow:: Node getAnUntrustedSource ( ) {
111
+ any ( UntrustedDataToExternalAPIConfig c ) .hasFlow ( result , this )
104
112
}
113
+ }
105
114
106
- /** A node representing untrusted data being passed to an external API. */
107
- class UntrustedExternalAPIDataNode extends ExternalAPIDataNode {
108
- UntrustedExternalAPIDataNode ( ) { any ( UntrustedDataToExternalAPIConfig c ) .hasFlow ( _, this ) }
115
+ private newtype TExternalAPI =
116
+ TExternalAPIParameter ( Method m , int index ) {
117
+ exists ( UntrustedExternalAPIDataNode n |
118
+ m = n .getMethod ( ) and
119
+ index = n .getIndex ( )
120
+ )
121
+ }
122
+
123
+ /** An external API which is used with untrusted data. */
124
+ class ExternalAPIUsedWithUntrustedData extends TExternalAPI {
125
+ /** Gets a possibly untrusted use of this external API. */
126
+ UntrustedExternalAPIDataNode getUntrustedDataNode ( ) {
127
+ this = TExternalAPIParameter ( result .getMethod ( ) , result .getIndex ( ) )
128
+ }
109
129
110
- /** Gets a source of untrusted data which is passed to this external API data node. */
111
- DataFlow:: Node getAnUntrustedSource ( ) {
112
- any ( UntrustedDataToExternalAPIConfig c ) .hasFlow ( result , this )
113
- }
130
+ /** Gets the number of untrusted sources used with this external API. */
131
+ int getNumberOfUntrustedSources ( ) {
132
+ result = count ( getUntrustedDataNode ( ) .getAnUntrustedSource ( ) )
114
133
}
115
134
116
- private newtype TExternalAPI =
117
- TExternalAPIParameter ( Method m , int index ) {
118
- exists ( UntrustedExternalAPIDataNode n |
119
- m = n .getMethod ( ) and
120
- index = n .getIndex ( )
121
- )
122
- }
123
-
124
- /** An external API which is used with untrusted data. */
125
- class ExternalAPIUsedWithUntrustedData extends TExternalAPI {
126
- /** Gets a possibly untrusted use of this external API. */
127
- UntrustedExternalAPIDataNode getUntrustedDataNode ( ) {
128
- this = TExternalAPIParameter ( result .getMethod ( ) , result .getIndex ( ) )
129
- }
130
-
131
- /** Gets the number of untrusted sources used with this external API. */
132
- int getNumberOfUntrustedSources ( ) {
133
- result = count ( getUntrustedDataNode ( ) .getAnUntrustedSource ( ) )
134
- }
135
-
136
- string toString ( ) {
137
- exists ( Method m , int index , string indexString |
138
- if index = - 1 then indexString = "qualifier" else indexString = "param " + index
139
- |
140
- this = TExternalAPIParameter ( m , index ) and
141
- result =
142
- m .getDeclaringType ( ) .( RefType ) .getQualifiedName ( ) + "." + m .getSignature ( ) + " [" + indexString + "]"
143
- )
144
- }
135
+ /** Gets a textual representation of this element. */
136
+ string toString ( ) {
137
+ exists ( Method m , int index , string indexString |
138
+ if index = - 1 then indexString = "qualifier" else indexString = "param " + index
139
+ |
140
+ this = TExternalAPIParameter ( m , index ) and
141
+ result =
142
+ m .getDeclaringType ( ) .( RefType ) .getQualifiedName ( ) + "." + m .getSignature ( ) + " [" +
143
+ indexString + "]"
144
+ )
145
145
}
146
146
}
0 commit comments