Skip to content

Account for JaxRS filters #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 57 additions & 9 deletions java/src/security/CWE-022/UnsafeURICheck.ql
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,81 @@ import java
import semmle.code.java.dataflow.FlowSources
import UnsafeURICheckFlow::PathGraph

// Reference: https://mail-archives.apache.org/mod_mbox/ambari-user/202102.mbox/%3CCAEJYuxEQZ_aPwJdAaSxPu-Dva%3Dhc7zZUx3-pzBORbd23g%2BGH1A%40mail.gmail.com%3E
// Example: https://mail-archives.apache.org/mod_mbox/ambari-user/202102.mbox/%3CCAEJYuxEQZ_aPwJdAaSxPu-Dva%3Dhc7zZUx3-pzBORbd23g%2BGH1A%40mail.gmail.com%3E
class ServletFilterInterface extends Interface {
ServletFilterInterface() { this.hasQualifiedName("javax.servlet", "Filter") }
}

class ContainerRequestFilterInterface extends Interface {
ContainerRequestFilterInterface() {
this.hasQualifiedName("javax.ws.rs.container", "ContainerRequestFilter")
}
}

class ServletRequestInterface extends Interface {
ServletRequestInterface() { this.hasQualifiedName("javax.servlet.http", "HttpServletRequest") }
}

class GetRequestURIMethodAccess extends MethodAccess {
GetRequestURIMethodAccess() {
class UriInfoType extends RefType {
UriInfoType() { this.hasQualifiedName("javax.ws.rs.core", "UriInfo") }
}

abstract class FilterMethod extends Method { }

string getSecurityFilterRegexp() { result = ".*(auth|security|jwt|allow|block|login).*" }

class FilterContainerRequestFilterMethod extends FilterMethod {
FilterContainerRequestFilterMethod() {
exists(Method m |
this.overrides*(m) and
m.getName() = "filter" and
m.getDeclaringType() instanceof ContainerRequestFilterInterface and
this.getDeclaringType().getName().toLowerCase().regexpMatch(getSecurityFilterRegexp())
)
}
}

class DoFilterServletRequestMethod extends FilterMethod {
DoFilterServletRequestMethod() {
exists(Method m |
this.overrides*(m) and
m.getName() = "doFilter" and
m.getDeclaringType() instanceof ServletFilterInterface and
this.getDeclaringType().getName().toLowerCase().regexpMatch(getSecurityFilterRegexp())
)
}
}

abstract class GetUriPathCall extends MethodCall { }

class GetRequestURIMethodCall extends GetUriPathCall {
GetRequestURIMethodCall() {
this.getMethod().getName() = "getRequestURI" and
this.getMethod().getDeclaringType() instanceof ServletRequestInterface
}
}

class UriInfoGetPathMethodCall extends GetUriPathCall {
UriInfoGetPathMethodCall() {
this.getMethod().getName() = "getPath" and
this.getMethod().getDeclaringType() instanceof UriInfoType
}
}

private module UnsafeURICheckConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(GetRequestURIMethodAccess ma |
ma.getEnclosingCallable().getDeclaringType().getASourceSupertype*() instanceof
ServletFilterInterface and
source.asExpr() = ma
exists(GetUriPathCall call, FilterMethod m |
source.asExpr() = call and
(
m.polyCalls*(call.getEnclosingCallable()) or
m.polyCalls*(call.getEnclosingCallable().getEnclosingCallable()) or
m.polyCalls*(call.getEnclosingCallable().getEnclosingCallable().getEnclosingCallable())
)
)
}

predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
exists(MethodCall ma |
// java.util.regex.Pattern.matcher("aaaaab");
ma.getMethod().getName() = "matcher" and
ma.getMethod().getDeclaringType().hasQualifiedName("java.util.regex", "Pattern") and
Expand All @@ -54,7 +102,7 @@ private module UnsafeURICheckConfig implements DataFlow::ConfigSig {
ma.getMethod().getDeclaringType() instanceof TypeString and
sink.asExpr() = ma.getQualifier()
or
ma.getMethod().getName() = ["startsWith", "endsWith"] and
ma.getMethod().getName() = ["contains", "startsWith", "endsWith"] and
ma.getMethod().getDeclaringType() instanceof TypeString and
not ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "/" and
sink.asExpr() = ma.getQualifier()
Expand Down