@@ -7,8 +7,7 @@ import semmle.code.java.frameworks.spring.Spring
7
7
import semmle.code.java.frameworks.JaxWS
8
8
import semmle.code.java.frameworks.javase.Http
9
9
import semmle.code.java.dataflow.DataFlow
10
- import semmle.code.java.dataflow.TaintTracking
11
- private import semmle.code.java.StringFormat
10
+ private import semmle.code.java.dataflow.StringPrefixes
12
11
private import semmle.code.java.dataflow.ExternalFlow
13
12
14
13
/**
@@ -52,10 +51,10 @@ private class PrimitiveSanitizer extends RequestForgerySanitizer {
52
51
}
53
52
}
54
53
55
- private class HostnameSanitizingConstantPrefix extends CompileTimeConstantExpr {
54
+ private class HostnameSanitizingPrefix extends InterestingPrefix {
56
55
int offset ;
57
56
58
- HostnameSanitizingConstantPrefix ( ) {
57
+ HostnameSanitizingPrefix ( ) {
59
58
// Matches strings that look like when prepended to untrusted input, they will restrict
60
59
// the host or entity addressed: for example, anything containing `?` or `#`, or a slash that
61
60
// doesn't appear to be a protocol specifier (e.g. `http://` is not sanitizing), or specifically
@@ -66,149 +65,13 @@ private class HostnameSanitizingConstantPrefix extends CompileTimeConstantExpr {
66
65
)
67
66
}
68
67
69
- /**
70
- * Gets the offset in this constant string where a sanitizing substring begins.
71
- */
72
- int getOffset ( ) { result = offset }
73
- }
74
-
75
- private Expr getAHostnameSanitizingPrefix ( ) {
76
- result instanceof HostnameSanitizingConstantPrefix
77
- or
78
- result .( AddExpr ) .getAnOperand ( ) = getAHostnameSanitizingPrefix ( )
79
- }
80
-
81
- private class StringBuilderAppend extends MethodAccess {
82
- StringBuilderAppend ( ) {
83
- this .getMethod ( ) .getDeclaringType ( ) instanceof StringBuildingType and
84
- this .getMethod ( ) .hasName ( "append" )
85
- }
86
- }
87
-
88
- private class StringBuilderConstructorOrAppend extends Call {
89
- StringBuilderConstructorOrAppend ( ) {
90
- this instanceof StringBuilderAppend or
91
- this .( ClassInstanceExpr ) .getConstructedType ( ) instanceof StringBuildingType
92
- }
93
- }
94
-
95
- private Expr getQualifier ( Expr e ) { result = e .( MethodAccess ) .getQualifier ( ) }
96
-
97
- /**
98
- * An extension of `StringBuilderVar` that also accounts for strings appended in StringBuilder/Buffer's constructor
99
- * and in `append` calls chained onto the constructor call.
100
- *
101
- * The original `StringBuilderVar` doesn't care about these because it is designed to model taint, and
102
- * in taint rules terms these are not needed, as the connection between construction, appends and the
103
- * eventual `toString` is more obvious.
104
- */
105
- private class StringBuilderVarExt extends StringBuilderVar {
106
- /**
107
- * Returns a first assignment after this StringBuilderVar is first assigned.
108
- *
109
- * For example, for `StringBuilder sbv = new StringBuilder("1").append("2"); sbv.append("3").append("4");`
110
- * this returns the append of `"3"`.
111
- */
112
- private StringBuilderAppend getAFirstAppendAfterAssignment ( ) {
113
- result = this .getAnAppend ( ) and not result = this .getNextAppend ( _)
114
- }
115
-
116
- /**
117
- * Gets the next `append` after `prev`, where `prev` is, perhaps after some more `append` or other
118
- * chained calls, assigned to this `StringBuilderVar`.
119
- */
120
- private StringBuilderAppend getNextAssignmentChainedAppend ( StringBuilderConstructorOrAppend prev ) {
121
- getQualifier * ( result ) = this .getAnAssignedValue ( ) and
122
- result .getQualifier ( ) = prev
123
- }
124
-
125
- /**
126
- * Get a constructor call or `append` call that contributes a string to this string builder.
127
- */
128
- StringBuilderConstructorOrAppend getAConstructorOrAppend ( ) {
129
- exists ( this .getNextAssignmentChainedAppend ( result ) ) or
130
- result = this .getAnAssignedValue ( ) or
131
- result = this .getAnAppend ( )
132
- }
133
-
134
- /**
135
- * Like `StringBuilderVar.getNextAppend`, except including appends and constructors directly
136
- * assigned to this `StringBuilderVar`.
137
- */
138
- private StringBuilderAppend getNextAppendIncludingAssignmentChains (
139
- StringBuilderConstructorOrAppend prev
140
- ) {
141
- result = this .getNextAssignmentChainedAppend ( prev )
142
- or
143
- prev = this .getAnAssignedValue ( ) and
144
- result = this .getAFirstAppendAfterAssignment ( )
145
- or
146
- result = this .getNextAppend ( prev )
147
- }
148
-
149
- /**
150
- * Implements `StringBuilderVarExt.getNextAppendIncludingAssignmentChains+(prev)`.
151
- */
152
- pragma [ nomagic]
153
- StringBuilderAppend getSubsequentAppendIncludingAssignmentChains (
154
- StringBuilderConstructorOrAppend prev
155
- ) {
156
- result = this .getNextAppendIncludingAssignmentChains ( prev ) or
157
- result =
158
- this .getSubsequentAppendIncludingAssignmentChains ( this .getNextAppendIncludingAssignmentChains ( prev ) )
159
- }
160
- }
161
-
162
- /**
163
- * An expression that is sanitized because it is concatenated onto a string that looks like
164
- * a hostname or a URL separator, preventing the appended string from arbitrarily controlling
165
- * the addressed server.
166
- */
167
- private class HostnameSanitizedExpr extends Expr {
168
- HostnameSanitizedExpr ( ) {
169
- // Sanitize expressions that come after a sanitizing prefix in a tree of string additions:
170
- this =
171
- any ( AddExpr add | add .getLeftOperand ( ) = getAHostnameSanitizingPrefix ( ) ) .getRightOperand ( )
172
- or
173
- // Sanitize expressions that come after a sanitizing prefix in a sequence of StringBuilder operations:
174
- exists (
175
- StringBuilderConstructorOrAppend appendSanitizingConstant ,
176
- StringBuilderAppend subsequentAppend , StringBuilderVarExt v
177
- |
178
- appendSanitizingConstant = v .getAConstructorOrAppend ( ) and
179
- appendSanitizingConstant .getArgument ( 0 ) = getAHostnameSanitizingPrefix ( ) and
180
- v .getSubsequentAppendIncludingAssignmentChains ( appendSanitizingConstant ) = subsequentAppend and
181
- this = subsequentAppend .getArgument ( 0 )
182
- )
183
- or
184
- // Sanitize expressions that come after a sanitizing prefix in the args to a format call:
185
- exists (
186
- FormattingCall formatCall , FormatString formatString , HostnameSanitizingConstantPrefix prefix ,
187
- int sanitizedFromOffset , int laterOffset , int sanitizedArg
188
- |
189
- formatString = unique( FormatString fs | fs = formatCall .getAFormatString ( ) ) and
190
- (
191
- // A sanitizing argument comes before this:
192
- exists ( int argIdx |
193
- formatCall .getArgumentToBeFormatted ( argIdx ) = prefix and
194
- sanitizedFromOffset = formatString .getAnArgUsageOffset ( argIdx )
195
- )
196
- or
197
- // The format string itself sanitizes subsequent arguments:
198
- formatString = prefix .getStringValue ( ) and
199
- sanitizedFromOffset = prefix .getOffset ( )
200
- ) and
201
- laterOffset > sanitizedFromOffset and
202
- laterOffset = formatString .getAnArgUsageOffset ( sanitizedArg ) and
203
- this = formatCall .getArgumentToBeFormatted ( sanitizedArg )
204
- )
205
- }
68
+ override int getOffset ( ) { result = offset }
206
69
}
207
70
208
71
/**
209
72
* A value that is the result of prepending a string that prevents any value from controlling the
210
73
* host of a URL.
211
74
*/
212
75
private class HostnameSantizer extends RequestForgerySanitizer {
213
- HostnameSantizer ( ) { this .asExpr ( ) instanceof HostnameSanitizedExpr }
76
+ HostnameSantizer ( ) { this .asExpr ( ) = any ( HostnameSanitizingPrefix hsp ) . getAnAppendedExpression ( ) }
214
77
}
0 commit comments