|
| 1 | +/** Provides configurations to be used in queries related to regex injection. */ |
| 2 | + |
1 | 3 | import java
|
2 | 4 | import semmle.code.java.dataflow.FlowSources
|
3 | 5 | import semmle.code.java.dataflow.TaintTracking
|
4 |
| -import semmle.code.java.regex.RegexFlowConfigs |
5 |
| - |
6 |
| -/** The Java class `java.util.regex.Pattern`. */ |
7 |
| -private class RegexPattern extends RefType { |
8 |
| - RegexPattern() { this.hasQualifiedName("java.util.regex", "Pattern") } |
9 |
| -} |
10 |
| - |
11 |
| -/** The Java class `java.util.regex.Matcher`. */ |
12 |
| -private class RegexMatcher extends RefType { |
13 |
| - RegexMatcher() { this.hasQualifiedName("java.util.regex", "Matcher") } |
14 |
| -} |
15 |
| - |
16 |
| -/** The Java class `org.apache.commons.lang3.RegExUtils`. */ |
17 |
| -private class ApacheRegExUtils extends RefType { |
18 |
| - ApacheRegExUtils() { this.hasQualifiedName("java.util.regex", "Matcher") } |
19 |
| -} |
20 |
| - |
21 |
| -// TODO: Look for above in pre-existing regex libraries again. |
22 |
| -// TODO: look into further: Pattern.matcher, .pattern() and .toString() as taint steps, .split and .splitAsStream |
23 |
| -/** |
24 |
| - * A data flow sink for untrusted user input used to construct regular expressions. |
25 |
| - */ |
26 |
| -class RegexSink extends DataFlow::ExprNode { |
27 |
| - RegexSink() { |
28 |
| - exists(MethodAccess ma, Method m | m = ma.getMethod() | |
29 |
| - ma.getArgument(0) = this.asExpr() and |
30 |
| - ( |
31 |
| - m.getDeclaringType() instanceof TypeString and |
32 |
| - m.hasName(["matches", "split", "replaceFirst", "replaceAll"]) |
33 |
| - or |
34 |
| - m.getDeclaringType() instanceof RegexPattern and |
35 |
| - m.hasName(["compile", "matches"]) |
36 |
| - ) |
37 |
| - or |
38 |
| - m.getDeclaringType() instanceof ApacheRegExUtils and |
39 |
| - ( |
40 |
| - ma.getArgument(1) = this.asExpr() and |
41 |
| - m.getParameterType(1) instanceof TypeString and // only does String here because other option is Pattern, but that's already handled by `java.util.regex.Pattern` above |
42 |
| - m.hasName([ |
43 |
| - "removeAll", "removeFirst", "removePattern", "replaceAll", "replaceFirst", |
44 |
| - "replacePattern" |
45 |
| - ]) |
46 |
| - ) |
47 |
| - ) |
48 |
| - } |
49 |
| -} |
50 |
| - |
51 |
| -// ! keep and rename to RegexInjectionSanitizer IF makes sense to have two sanitizers extending it?; |
52 |
| -// ! else, ask Tony/others about if stylistically better to keep it (see default example in LogInjection.qll, etc.) |
53 |
| -// ! maybe make abstract classes for source and sink as well (if you do this, mention it in PR description as an attempt to be similar to the other languages' implementations) |
54 |
| -abstract class Sanitizer extends DataFlow::ExprNode { } |
55 |
| - |
56 |
| -/** |
57 |
| - * A call to a function whose name suggests that it escapes regular |
58 |
| - * expression meta-characters. |
59 |
| - */ |
60 |
| -// ! rename as DefaultRegexInjectionSanitizer? |
61 |
| -class RegExpSanitizationCall extends Sanitizer { |
62 |
| - RegExpSanitizationCall() { |
63 |
| - exists(string calleeName, string sanitize, string regexp | |
64 |
| - calleeName = this.asExpr().(Call).getCallee().getName() and |
65 |
| - // ! add test case for sanitize? I think current tests only check escape |
66 |
| - sanitize = "(?:escape|saniti[sz]e)" and // TODO: confirm this is sufficient |
67 |
| - regexp = "regexp?" // TODO: confirm this is sufficient |
68 |
| - | |
69 |
| - calleeName |
70 |
| - .regexpMatch("(?i)(" + sanitize + ".*" + regexp + ".*)" + "|(" + regexp + ".*" + sanitize + |
71 |
| - ".*)") // TODO: confirm this is sufficient |
72 |
| - ) |
73 |
| - or |
74 |
| - // adds Pattern.quote() as a sanitizer |
75 |
| - // see https://rules.sonarsource.com/java/RSPEC-2631 and https://sensei.securecodewarrior.com/recipes/scw:java:regex-injection |
76 |
| - exists(MethodAccess ma, Method m | m = ma.getMethod() | |
77 |
| - m.getDeclaringType() instanceof RegexPattern and |
78 |
| - ( |
79 |
| - ma.getArgument(0) = this.asExpr() and |
80 |
| - m.hasName("quote") |
81 |
| - ) |
82 |
| - ) |
83 |
| - } |
84 |
| -} |
| 6 | +import semmle.code.java.security.RegexInjection |
85 | 7 |
|
86 | 8 | /**
|
87 | 9 | * A taint-tracking configuration for untrusted user input used to construct regular expressions.
|
88 | 10 | */
|
89 | 11 | class RegexInjectionConfiguration extends TaintTracking::Configuration {
|
90 |
| - RegexInjectionConfiguration() { this = "RegexInjectionConfiguration" } |
| 12 | + RegexInjectionConfiguration() { this = "RegexInjection" } |
91 | 13 |
|
92 | 14 | override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
93 | 15 |
|
94 |
| - override predicate isSink(DataFlow::Node sink) { sink instanceof RegexSink } |
| 16 | + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } |
95 | 17 |
|
96 |
| - // ! testing below RegexFlowSink from RegexFlowConfigs.qll |
97 |
| - // ! extra results from jfinal with this... look into further... |
98 |
| - // override predicate isSink(DataFlow::Node sink) { sink instanceof RegexFlowSink } |
99 | 18 | override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
|
100 | 19 | }
|
0 commit comments