@@ -7,9 +7,37 @@ import semmle.code.java.frameworks.spring.SpringWeb
77import semmle.code.java.security.RequestForgery
88private import semmle.code.java.dataflow.StringPrefixes
99
10- /** A sanitizer for unsafe url forward vulnerabilities. */
10+ /** A sink for unsafe URL forward vulnerabilities. */
11+ abstract class UnsafeUrlForwardSink extends DataFlow:: Node { }
12+
13+ /** A sanitizer for unsafe URL forward vulnerabilities. */
1114abstract class UnsafeUrlForwardSanitizer extends DataFlow:: Node { }
1215
16+ /** A barrier guard that protects against URL forward vulnerabilities. */
17+ abstract class UnsafeUrlForwardBarrierGuard extends DataFlow:: BarrierGuard { }
18+
19+ /** An argument to `getRequestDispatcher`. */
20+ private class RequestDispatcherSink extends UnsafeUrlForwardSink {
21+ RequestDispatcherSink ( ) {
22+ exists ( MethodAccess ma |
23+ ma .getMethod ( ) instanceof GetRequestDispatcherMethod and
24+ ma .getArgument ( 0 ) = this .asExpr ( )
25+ )
26+ }
27+ }
28+
29+ /** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
30+ private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
31+ SpringModelAndViewSink ( ) {
32+ exists ( ClassInstanceExpr cie |
33+ cie .getConstructedType ( ) instanceof ModelAndView and
34+ cie .getArgument ( 0 ) = this .asExpr ( )
35+ )
36+ or
37+ exists ( SpringModelAndViewSetViewNameCall smavsvnc | smavsvnc .getArgument ( 0 ) = this .asExpr ( ) )
38+ }
39+ }
40+
1341private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
1442 PrimitiveSanitizer ( ) {
1543 this .getType ( ) instanceof PrimitiveType or
@@ -31,74 +59,6 @@ private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
3159 FollowsSanitizingPrefix ( ) { this .asExpr ( ) = any ( SanitizingPrefix fp ) .getAnAppendedExpression ( ) }
3260}
3361
34- /** A barrier guard that protects against URL forward vulnerabilities. */
35- abstract class UnsafeUrlForwardBarrierGuard extends DataFlow:: BarrierGuard { }
36-
37- /**
38- * Holds if `ma` is a call to a method that checks a path string.
39- */
40- private predicate isStringPathMatch ( MethodAccess ma ) {
41- ma .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
42- ma .getMethod ( ) .getName ( ) =
43- [ "contains" , "startsWith" , "matches" , "regionMatches" , "indexOf" , "lastIndexOf" ]
44- }
45-
46- /**
47- * Holds if `ma` is a call to a method of `java.nio.file.Path` that checks a path.
48- */
49- private predicate isFilePathMatch ( MethodAccess ma ) {
50- ma .getMethod ( ) .getDeclaringType ( ) instanceof TypePath and
51- ma .getMethod ( ) .getName ( ) = "startsWith"
52- }
53-
54- /** A complementary guard that protects against path traversal, by looking for the literal `..`. */
55- private class PathTraversalGuard extends Guard instanceof MethodAccess {
56- Expr checked ;
57-
58- PathTraversalGuard ( ) {
59- this .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
60- this .getMethod ( ) .hasName ( [ "contains" , "indexOf" ] ) and
61- this .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = ".." and
62- this .controls ( checked .getBasicBlock ( ) , false )
63- }
64-
65- predicate checks ( Expr e ) { checked = e }
66- }
67-
68- /** A complementary sanitizer that protects against path traversal using path normalization. */
69- private class PathNormalizeSanitizer extends MethodAccess {
70- PathNormalizeSanitizer ( ) {
71- this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "java.nio.file" , "Path" ) and
72- this .getMethod ( ) .hasName ( "normalize" )
73- }
74- }
75-
76- /** A complementary guard that protects against double URL encoding, by looking for the literal `%`. */
77- private class UrlEncodingGuard extends Guard instanceof MethodAccess {
78- Expr checked ;
79-
80- UrlEncodingGuard ( ) {
81- this .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
82- this .getMethod ( ) .hasName ( [ "contains" , "indexOf" ] ) and
83- this .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "%" and
84- this .controls ( checked .getBasicBlock ( ) , false )
85- }
86-
87- predicate checks ( Expr e ) { checked = e }
88- }
89-
90- /** A complementary sanitizer that protects against double URL encoding using URL decoding. */
91- private class UrlDecodeSanitizer extends MethodAccess {
92- UrlDecodeSanitizer ( ) {
93- this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "java.net" , "URLDecoder" ) and
94- this .getMethod ( ) .hasName ( "decode" )
95- }
96- }
97-
98- private predicate isDisallowedWord ( CompileTimeConstantExpr word ) {
99- word .getStringValue ( ) .matches ( [ "%WEB-INF%" , "%META-INF%" , "%..%" ] )
100- }
101-
10262/**
10363 * A guard that considers safe a string being exactly compared to a trusted value.
10464 */
@@ -176,27 +136,68 @@ private class BlockListCheckGuard extends UnsafeUrlForwardBarrierGuard instanceo
176136 }
177137}
178138
179- abstract class UnsafeUrlForwardSink extends DataFlow:: Node { }
139+ /**
140+ * Holds if `ma` is a call to a method that checks a path string.
141+ */
142+ private predicate isStringPathMatch ( MethodAccess ma ) {
143+ ma .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
144+ ma .getMethod ( ) .getName ( ) =
145+ [ "contains" , "startsWith" , "matches" , "regionMatches" , "indexOf" , "lastIndexOf" ]
146+ }
180147
181- /** An argument to `getRequestDispatcher`. */
182- private class RequestDispatcherSink extends UnsafeUrlForwardSink {
183- RequestDispatcherSink ( ) {
184- exists ( MethodAccess ma |
185- ma .getMethod ( ) instanceof GetRequestDispatcherMethod and
186- ma .getArgument ( 0 ) = this .asExpr ( )
187- )
148+ /**
149+ * Holds if `ma` is a call to a method of `java.nio.file.Path` that checks a path.
150+ */
151+ private predicate isFilePathMatch ( MethodAccess ma ) {
152+ ma .getMethod ( ) .getDeclaringType ( ) instanceof TypePath and
153+ ma .getMethod ( ) .getName ( ) = "startsWith"
154+ }
155+
156+ private predicate isDisallowedWord ( CompileTimeConstantExpr word ) {
157+ word .getStringValue ( ) .matches ( [ "%WEB-INF%" , "%META-INF%" , "%..%" ] )
158+ }
159+
160+ /** A complementary guard that protects against path traversal, by looking for the literal `..`. */
161+ private class PathTraversalGuard extends Guard instanceof MethodAccess {
162+ Expr checked ;
163+
164+ PathTraversalGuard ( ) {
165+ this .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
166+ this .getMethod ( ) .hasName ( [ "contains" , "indexOf" ] ) and
167+ this .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = ".." and
168+ this .controls ( checked .getBasicBlock ( ) , false )
188169 }
170+
171+ predicate checks ( Expr e ) { checked = e }
189172}
190173
191- /** An argument to `new ModelAndView` or `ModelAndView.setViewName`. */
192- private class SpringModelAndViewSink extends UnsafeUrlForwardSink {
193- SpringModelAndViewSink ( ) {
194- exists ( ClassInstanceExpr cie |
195- cie .getConstructedType ( ) instanceof ModelAndView and
196- cie .getArgument ( 0 ) = this .asExpr ( )
197- )
198- or
199- exists ( SpringModelAndViewSetViewNameCall smavsvnc | smavsvnc .getArgument ( 0 ) = this .asExpr ( ) )
174+ /** A complementary sanitizer that protects against path traversal using path normalization. */
175+ private class PathNormalizeSanitizer extends MethodAccess {
176+ PathNormalizeSanitizer ( ) {
177+ this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "java.nio.file" , "Path" ) and
178+ this .getMethod ( ) .hasName ( "normalize" )
179+ }
180+ }
181+
182+ /** A complementary guard that protects against double URL encoding, by looking for the literal `%`. */
183+ private class UrlEncodingGuard extends Guard instanceof MethodAccess {
184+ Expr checked ;
185+
186+ UrlEncodingGuard ( ) {
187+ this .getMethod ( ) .getDeclaringType ( ) instanceof TypeString and
188+ this .getMethod ( ) .hasName ( [ "contains" , "indexOf" ] ) and
189+ this .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "%" and
190+ this .controls ( checked .getBasicBlock ( ) , false )
191+ }
192+
193+ predicate checks ( Expr e ) { checked = e }
194+ }
195+
196+ /** A complementary sanitizer that protects against double URL encoding using URL decoding. */
197+ private class UrlDecodeSanitizer extends MethodAccess {
198+ UrlDecodeSanitizer ( ) {
199+ this .getMethod ( ) .getDeclaringType ( ) .hasQualifiedName ( "java.net" , "URLDecoder" ) and
200+ this .getMethod ( ) .hasName ( "decode" )
200201 }
201202}
202203
0 commit comments