@@ -7,8 +7,7 @@ import semmle.code.java.frameworks.spring.Spring
77import semmle.code.java.frameworks.JaxWS
88import semmle.code.java.frameworks.javase.Http
99import 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
1211private import semmle.code.java.dataflow.ExternalFlow
1312
1413/**
@@ -52,10 +51,10 @@ private class PrimitiveSanitizer extends RequestForgerySanitizer {
5251 }
5352}
5453
55- private class HostnameSanitizingConstantPrefix extends CompileTimeConstantExpr {
54+ private class HostnameSanitizingPrefix extends InterestingPrefix {
5655 int offset ;
5756
58- HostnameSanitizingConstantPrefix ( ) {
57+ HostnameSanitizingPrefix ( ) {
5958 // Matches strings that look like when prepended to untrusted input, they will restrict
6059 // the host or entity addressed: for example, anything containing `?` or `#`, or a slash that
6160 // 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 {
6665 )
6766 }
6867
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 }
20669}
20770
20871/**
20972 * A value that is the result of prepending a string that prevents any value from controlling the
21073 * host of a URL.
21174 */
21275private class HostnameSantizer extends RequestForgerySanitizer {
213- HostnameSantizer ( ) { this .asExpr ( ) instanceof HostnameSanitizedExpr }
76+ HostnameSantizer ( ) { this .asExpr ( ) = any ( HostnameSanitizingPrefix hsp ) . getAnAppendedExpression ( ) }
21477}
0 commit comments