Skip to content
Merged
Show file tree
Hide file tree
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* A sanitizer has been added to `java/ssrf` to remove alerts when a regular expression check is used to verify that the value is safe.
35 changes: 35 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/Regex.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,46 @@ module;

import java

/** The class `java.util.regex.Matcher`. */
class TypeRegexMatcher extends Class {
TypeRegexMatcher() { this.hasQualifiedName("java.util.regex", "Matcher") }
}

/**
* The `matches` method of `java.util.regex.Matcher`.
*/
class MatcherMatchesMethod extends Method {
MatcherMatchesMethod() {
this.getDeclaringType() instanceof TypeRegexMatcher and
this.hasName("matches")
}
}

/** The class `java.util.regex.Pattern`. */
class TypeRegexPattern extends Class {
TypeRegexPattern() { this.hasQualifiedName("java.util.regex", "Pattern") }
}

/**
* The `matches` method of `java.util.regex.Pattern`.
*/
class PatternMatchesMethod extends Method {
PatternMatchesMethod() {
this.getDeclaringType() instanceof TypeRegexPattern and
this.hasName("matches")
}
}

/**
* The `matcher` method of `java.util.regex.Pattern`.
*/
class PatternMatcherMethod extends Method {
PatternMatcherMethod() {
this.getDeclaringType() instanceof TypeRegexPattern and
this.hasName("matcher")
}
}

/** The `quote` method of the `java.util.regex.Pattern` class. */
class PatternQuoteMethod extends Method {
PatternQuoteMethod() {
Expand Down
21 changes: 3 additions & 18 deletions java/ql/lib/semmle/code/java/security/RequestForgery.qll
Original file line number Diff line number Diff line change
Expand Up @@ -166,22 +166,7 @@ private class HostComparisonSanitizer extends RequestForgerySanitizer {
}

/**
* A qualifier in a call to a `.matches()` method that is a sanitizer for URL redirects.
*
* Matches any method call where the method is named `matches`.
*/
private predicate isMatchesSanitizer(Guard guard, Expr e, boolean branch) {
guard =
any(MethodCall method |
method.getMethod().getName() = "matches" and
e = method.getQualifier() and
branch = true
)
}

/**
* A qualifier in a call to `.matches()` that is a sanitizer for URL redirects.
* A comparison with a regular expression that is a sanitizer for URL redirects.
*/
private class MatchesSanitizer extends RequestForgerySanitizer {
MatchesSanitizer() { this = DataFlow::BarrierGuard<isMatchesSanitizer/3>::getABarrierNode() }
}
private class RegexpCheckRequestForgerySanitizer extends RequestForgerySanitizer instanceof RegexpCheckBarrier
{ }
43 changes: 43 additions & 0 deletions java/ql/lib/semmle/code/java/security/Sanitizers.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ overlay[local?]
module;

import java
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.frameworks.Regex

/**
* A node whose type is a simple type unlikely to carry taint, such as primitives and their boxed counterparts,
Expand All @@ -29,3 +31,44 @@ class SimpleTypeSanitizer extends DataFlow::Node {
this.getType() instanceof EnumType
}
}

/**
* Holds if `guard` holds with branch `branch` if `e` matches a regular expression.
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*
* Use this if you want to define a derived `DataFlow::BarrierGuard` without
* make the type recursive. Otherwise use `RegexpCheckBarrier`.
*/
predicate regexpMatchGuardChecks(Guard guard, Expr e, boolean branch) {
exists(Method method, MethodCall mc |
method = mc.getMethod() and
guard = mc and
branch = true
|
// `String.matches` and other `matches` methods.
method.getName() = "matches" and
e = mc.getQualifier()
or
method instanceof PatternMatchesMethod and
e = mc.getArgument(1)
or
method instanceof MatcherMatchesMethod and
exists(MethodCall matcherCall |
matcherCall.getMethod() instanceof PatternMatcherMethod and
e = matcherCall.getArgument(0) and
DataFlow::localExprFlow(matcherCall, mc.getQualifier())
)
)
}

/**
* A check against a regular expression, considered as a barrier guard.
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
class RegexpCheckBarrier extends DataFlow::Node {
RegexpCheckBarrier() {
this = DataFlow::BarrierGuard<regexpMatchGuardChecks/3>::getABarrierNode()
}
}
Loading
Loading