11import java
22import DataFlow
3- import semmle.code.java.dataflow.DataFlow
3+ import semmle.code.java.dataflow.TaintTracking2
4+ import semmle.code.java.security.QueryInjection
45import experimental.semmle.code.java.Logging
56
6- /** A data flow source of the value of the `x-forwarded-for` field in the `header`. */
7+ /**
8+ * A data flow source of the client ip obtained according to the remote endpoint identifier specified
9+ * in the header (`X-Forwarded-For`, `X-Real-IP`, `Proxy-Client-IP`, etc.).
10+ *
11+ * For example: `ServletRequest.getHeader("X-Forwarded-For")`.
12+ */
713class UseOfLessTrustedSource extends DataFlow:: Node {
814 UseOfLessTrustedSource ( ) {
915 exists ( MethodAccess ma |
1016 ma .getMethod ( ) .hasName ( "getHeader" ) and
11- ma .getArgument ( 0 ) .toString ( ) .toLowerCase ( ) = "\"x-forwarded-for\"" and
17+ ma .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) .toLowerCase ( ) in [
18+ "x-forwarded-for" , "x-real-ip" , "proxy-client-ip" , "wl-proxy-client-ip" ,
19+ "http_x_forwarded_for" , "http_x_forwarded" , "http_x_cluster_client_ip" , "http_client_ip" ,
20+ "http_forwarded_for" , "http_forwarded" , "http_via" , "remote_addr"
21+ ] and
1222 ma = this .asExpr ( )
1323 )
1424 }
1525}
1626
17- /** A data flow sink of method return or log output or local print. */
18- class UseOfLessTrustedSink extends DataFlow:: Node {
19- UseOfLessTrustedSink ( ) {
20- exists ( ReturnStmt rs | rs .getResult ( ) = this .asExpr ( ) )
21- or
27+ /** A data flow sink for ip address forgery vulnerabilities. */
28+ abstract class UseOfLessTrustedSink extends DataFlow:: Node { }
29+
30+ /**
31+ * A data flow sink for the if condition, which does not include the null judgment of the remote client ip address.
32+ *
33+ * For example: `if (!StringUtils.startsWith(ipAddr, "192.168.")){...` determine whether the client ip starts
34+ * with `192.168.`, and the program can be deceived by forging the ip address.
35+ * `if (remoteAddr == null || "".equals(remoteAddr)) {...` judging whether the client ip is a null value,
36+ * it needs to be excluded
37+ */
38+ private class IfConditionSink extends UseOfLessTrustedSink {
39+ IfConditionSink ( ) {
40+ exists ( IfStmt is |
41+ is .getCondition ( ) = this .asExpr ( ) and
42+ not exists ( EQExpr eqe |
43+ eqe .getAnOperand ( ) instanceof NullLiteral and
44+ is .getCondition ( ) = eqe .getParent * ( )
45+ ) and
46+ not exists ( NEExpr nee |
47+ nee .getAnOperand ( ) instanceof NullLiteral and
48+ is .getCondition ( ) = nee .getParent * ( )
49+ ) and
50+ not exists ( MethodAccess ma |
51+ ma .getMethod ( ) .hasName ( "equals" ) and
52+ ma .getMethod ( ) .getNumberOfParameters ( ) = 1 and
53+ (
54+ ma .getQualifier ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "" or
55+ ma .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = ""
56+ ) and
57+ is .getCondition ( ) = ma .getParent * ( )
58+ ) and
59+ not exists ( MethodAccess ma |
60+ ma .getMethod ( ) .hasName ( "equalsIgnoreCase" ) and
61+ ma .getMethod ( ) .getNumberOfParameters ( ) = 1 and
62+ (
63+ ma .getQualifier ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "unknown" or
64+ ma .getArgument ( 0 ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "unknown"
65+ ) and
66+ is .getCondition ( ) = ma .getParent * ( )
67+ ) and
68+ not exists ( MethodAccess ma |
69+ ma .getMethod ( ) .getName ( ) in [ "isEmpty" , "isNotEmpty" ] and
70+ ma .getMethod ( ) .getNumberOfParameters ( ) = 1 and
71+ is .getCondition ( ) = ma .getParent * ( )
72+ ) and
73+ not exists ( MethodAccess ma |
74+ (
75+ ma .getMethod ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "StringUtils" , "isBlank" ) or
76+ ma .getMethod ( ) .hasQualifiedName ( "org.apache.commons.lang3" , "StringUtils" , "isNotBlank" )
77+ ) and
78+ is .getCondition ( ) = ma .getParent * ( )
79+ ) and
80+ not exists ( MethodAccess ma |
81+ ma .getMethod ( )
82+ .hasQualifiedName ( "org.apache.commons.lang3" , "StringUtils" , "equalsIgnoreCase" ) and
83+ ma .getAnArgument ( ) .( CompileTimeConstantExpr ) .getStringValue ( ) = "unknown" and
84+ is .getCondition ( ) = ma .getParent * ( )
85+ )
86+ )
87+ }
88+ }
89+
90+ /** A data flow sink for sql operation. */
91+ private class SqlOperationSink extends UseOfLessTrustedSink {
92+ SqlOperationSink ( ) { this instanceof QueryInjectionSink }
93+ }
94+
95+ /** A data flow sink for log operation. */
96+ private class LogOperationSink extends UseOfLessTrustedSink {
97+ LogOperationSink ( ) { exists ( LoggingCall lc | lc .getAnArgument ( ) = this .asExpr ( ) ) }
98+ }
99+
100+ /** A data flow sink for local output. */
101+ private class PrintSink extends UseOfLessTrustedSink {
102+ PrintSink ( ) {
22103 exists ( MethodAccess ma |
23104 ma .getMethod ( ) .getName ( ) in [ "print" , "println" ] and
24105 (
@@ -27,8 +108,6 @@ class UseOfLessTrustedSink extends DataFlow::Node {
27108 ) and
28109 ma .getAnArgument ( ) = this .asExpr ( )
29110 )
30- or
31- exists ( LoggingCall lc | lc .getAnArgument ( ) = this .asExpr ( ) )
32111 }
33112}
34113
@@ -39,50 +118,3 @@ class SplitMethod extends Method {
39118 this .hasQualifiedName ( "java.lang" , "String" , "split" )
40119 }
41120}
42-
43- /**
44- * A call to the ServletRequest.getHeader method and the argument are
45- * `wl-proxy-client-ip`/`proxy-client-ip`/`http_client_ip`/`http_x_forwarded_for`/`x-real-ip`.
46- */
47- class HeaderIpCall extends MethodAccess {
48- HeaderIpCall ( ) {
49- this .getMethod ( ) .hasName ( "getHeader" ) and
50- this .getMethod ( )
51- .getDeclaringType ( )
52- .getASupertype * ( )
53- .hasQualifiedName ( "javax.servlet" , "ServletRequest" ) and
54- this .getArgument ( 0 ) .toString ( ) .toLowerCase ( ) in [
55- "\"wl-proxy-client-ip\"" , "\"proxy-client-ip\"" , "\"http_client_ip\"" ,
56- "\"http_x_forwarded_for\"" , "\"x-real-ip\""
57- ]
58- }
59- }
60-
61- /** A call to `ServletRequest.getRemoteAddr` method. */
62- class RemoteAddrCall extends MethodAccess {
63- RemoteAddrCall ( ) {
64- this .getMethod ( ) .hasName ( "getRemoteAddr" ) and
65- this .getMethod ( )
66- .getDeclaringType ( )
67- .getASupertype * ( )
68- .hasQualifiedName ( "javax.servlet" , "ServletRequest" )
69- }
70- }
71-
72- /** The first one in the method to get the ip value through `x-forwarded-for`. */
73- predicate xffIsFirstGet ( Node node ) {
74- exists ( HeaderIpCall hic |
75- node .getEnclosingCallable ( ) = hic .getEnclosingCallable ( ) and
76- node .getLocation ( ) .getEndLine ( ) < hic .getLocation ( ) .getEndLine ( )
77- )
78- or
79- exists ( RemoteAddrCall rac |
80- node .getEnclosingCallable ( ) = rac .getEnclosingCallable ( ) and
81- node .getLocation ( ) .getEndLine ( ) < rac .getLocation ( ) .getEndLine ( )
82- )
83- or
84- not exists ( HeaderIpCall hic , RemoteAddrCall rac |
85- node .getEnclosingCallable ( ) = hic .getEnclosingCallable ( ) and
86- node .getEnclosingCallable ( ) = rac .getEnclosingCallable ( )
87- )
88- }
0 commit comments