1+ /** Provides classes related to unsafe URL forwarding in Java. */
2+
13import java
24private import semmle.code.java.dataflow.ExternalFlow
35private import semmle.code.java.dataflow.FlowSources
46private import semmle.code.java.dataflow.StringPrefixes
5- private import semmle.code.java.frameworks.javaee.ejb.EJBRestrictions
67
78/** A sink for unsafe URL forward vulnerabilities. */
89abstract class UnsafeUrlForwardSink extends DataFlow:: Node { }
910
10- /** A sanitizer for unsafe URL forward vulnerabilities. */
11- abstract class UnsafeUrlForwardSanitizer extends DataFlow:: Node { }
12-
1311/** A default sink representing methods susceptible to unsafe URL forwarding. */
1412private class DefaultUnsafeUrlForwardSink extends UnsafeUrlForwardSink {
1513 DefaultUnsafeUrlForwardSink ( ) { sinkNode ( this , "url-forward" ) }
1614}
1715
16+ /**
17+ * An expression appended (perhaps indirectly) to `"forward:"`, and which
18+ * is reachable from a Spring entry point.
19+ */
20+ private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
21+ SpringUrlForwardSink ( ) {
22+ // TODO: check if can use MaD "Annotated" for `SpringRequestMappingMethod` or if too complicated for MaD (probably too complicated).
23+ any ( SpringRequestMappingMethod sqmm ) .polyCalls * ( this .getEnclosingCallable ( ) ) and
24+ this .asExpr ( ) = any ( ForwardPrefix fp ) .getAnAppendedExpression ( )
25+ }
26+ }
27+
28+ // TODO: should this potentially be "include:" as well? Or does that not work similarly?
29+ private class ForwardPrefix extends InterestingPrefix {
30+ ForwardPrefix ( ) { this .getStringValue ( ) = "forward:" }
31+
32+ override int getOffset ( ) { result = 0 }
33+ }
34+
35+ /** A sanitizer for unsafe URL forward vulnerabilities. */
36+ abstract class UnsafeUrlForwardSanitizer extends DataFlow:: Node { }
37+
1838private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
1939 PrimitiveSanitizer ( ) {
2040 this .getType ( ) instanceof PrimitiveType or
@@ -23,6 +43,11 @@ private class PrimitiveSanitizer extends UnsafeUrlForwardSanitizer {
2343 }
2444}
2545
46+ // TODO: double-check this sanitizer (and should I switch all "sanitizer" naming to "barrier" instead?)
47+ private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
48+ FollowsSanitizingPrefix ( ) { this .asExpr ( ) = any ( SanitizingPrefix fp ) .getAnAppendedExpression ( ) }
49+ }
50+
2651private class SanitizingPrefix extends InterestingPrefix {
2752 SanitizingPrefix ( ) {
2853 not this .getStringValue ( ) .matches ( "/WEB-INF/%" ) and
@@ -31,24 +56,3 @@ private class SanitizingPrefix extends InterestingPrefix {
3156
3257 override int getOffset ( ) { result = 0 }
3358}
34-
35- private class FollowsSanitizingPrefix extends UnsafeUrlForwardSanitizer {
36- FollowsSanitizingPrefix ( ) { this .asExpr ( ) = any ( SanitizingPrefix fp ) .getAnAppendedExpression ( ) }
37- }
38-
39- private class ForwardPrefix extends InterestingPrefix {
40- ForwardPrefix ( ) { this .getStringValue ( ) = "forward:" }
41-
42- override int getOffset ( ) { result = 0 }
43- }
44-
45- /**
46- * An expression appended (perhaps indirectly) to `"forward:"`, and which
47- * is reachable from a Spring entry point.
48- */
49- private class SpringUrlForwardSink extends UnsafeUrlForwardSink {
50- SpringUrlForwardSink ( ) {
51- any ( SpringRequestMappingMethod sqmm ) .polyCalls * ( this .getEnclosingCallable ( ) ) and
52- this .asExpr ( ) = any ( ForwardPrefix fp ) .getAnAppendedExpression ( )
53- }
54- }
0 commit comments