Merge pull request #11070 from jcogs33/java-regex-injection

Java: Promote regex injection query from experimental
This commit is contained in:
Jami
2022-11-21 15:04:26 -05:00
committed by GitHub
17 changed files with 225 additions and 245 deletions

View File

@@ -1,73 +0,0 @@
edges
| RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... |
| RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern |
| RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern |
| RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern |
| RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern |
| RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern |
| RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern |
| RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:36:68:42 | pattern : String |
| RegexInjection.java:68:32:68:43 | foo(...) : String | RegexInjection.java:68:26:68:52 | ... + ... |
| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:68:32:68:43 | foo(...) : String |
| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:71:14:71:23 | str : String |
| RegexInjection.java:71:14:71:23 | str : String | RegexInjection.java:72:12:72:14 | str : String |
| RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... |
| RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern |
| RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern |
| RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern |
| RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern |
| RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern |
| RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern |
nodes
| RegexInjection.java:13:22:13:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:16:26:16:47 | ... + ... | semmle.label | ... + ... |
| RegexInjection.java:20:22:20:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:23:24:23:30 | pattern | semmle.label | pattern |
| RegexInjection.java:27:22:27:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:30:31:30:37 | pattern | semmle.label | pattern |
| RegexInjection.java:34:22:34:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:37:29:37:35 | pattern | semmle.label | pattern |
| RegexInjection.java:41:22:41:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:44:34:44:40 | pattern | semmle.label | pattern |
| RegexInjection.java:51:22:51:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:54:28:54:34 | pattern | semmle.label | pattern |
| RegexInjection.java:58:22:58:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:61:28:61:34 | pattern | semmle.label | pattern |
| RegexInjection.java:65:22:65:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:68:26:68:52 | ... + ... | semmle.label | ... + ... |
| RegexInjection.java:68:32:68:43 | foo(...) : String | semmle.label | foo(...) : String |
| RegexInjection.java:68:36:68:42 | pattern : String | semmle.label | pattern : String |
| RegexInjection.java:71:14:71:23 | str : String | semmle.label | str : String |
| RegexInjection.java:72:12:72:14 | str : String | semmle.label | str : String |
| RegexInjection.java:84:22:84:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:90:26:90:47 | ... + ... | semmle.label | ... + ... |
| RegexInjection.java:100:22:100:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:103:40:103:46 | pattern | semmle.label | pattern |
| RegexInjection.java:107:22:107:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:110:42:110:48 | pattern | semmle.label | pattern |
| RegexInjection.java:114:22:114:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:117:44:117:50 | pattern | semmle.label | pattern |
| RegexInjection.java:121:22:121:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:124:41:124:47 | pattern | semmle.label | pattern |
| RegexInjection.java:128:22:128:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:131:43:131:49 | pattern | semmle.label | pattern |
| RegexInjection.java:143:22:143:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| RegexInjection.java:146:45:146:51 | pattern | semmle.label | pattern |
subpaths
| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:71:14:71:23 | str : String | RegexInjection.java:72:12:72:14 | str : String | RegexInjection.java:68:32:68:43 | foo(...) : String |
#select
| RegexInjection.java:16:26:16:47 | ... + ... | RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:13:22:13:52 | getParameter(...) | user-provided value |
| RegexInjection.java:23:24:23:30 | pattern | RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:20:22:20:52 | getParameter(...) | user-provided value |
| RegexInjection.java:30:31:30:37 | pattern | RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:27:22:27:52 | getParameter(...) | user-provided value |
| RegexInjection.java:37:29:37:35 | pattern | RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:34:22:34:52 | getParameter(...) | user-provided value |
| RegexInjection.java:44:34:44:40 | pattern | RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:41:22:41:52 | getParameter(...) | user-provided value |
| RegexInjection.java:54:28:54:34 | pattern | RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:51:22:51:52 | getParameter(...) | user-provided value |
| RegexInjection.java:61:28:61:34 | pattern | RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:58:22:58:52 | getParameter(...) | user-provided value |
| RegexInjection.java:68:26:68:52 | ... + ... | RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:26:68:52 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:65:22:65:52 | getParameter(...) | user-provided value |
| RegexInjection.java:90:26:90:47 | ... + ... | RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:84:22:84:52 | getParameter(...) | user-provided value |
| RegexInjection.java:103:40:103:46 | pattern | RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:100:22:100:52 | getParameter(...) | user-provided value |
| RegexInjection.java:110:42:110:48 | pattern | RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:107:22:107:52 | getParameter(...) | user-provided value |
| RegexInjection.java:117:44:117:50 | pattern | RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:114:22:114:52 | getParameter(...) | user-provided value |
| RegexInjection.java:124:41:124:47 | pattern | RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:121:22:121:52 | getParameter(...) | user-provided value |
| RegexInjection.java:131:43:131:49 | pattern | RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:128:22:128:52 | getParameter(...) | user-provided value |
| RegexInjection.java:146:45:146:51 | pattern | RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:143:22:143:52 | getParameter(...) | user-provided value |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-730/RegexInjection.ql

View File

@@ -1 +0,0 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/apache-commons-lang3-3.7

View File

@@ -7,128 +7,119 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import org.apache.commons.lang3.RegExUtils;
import com.google.common.base.Splitter;
public class RegexInjection extends HttpServlet {
public class RegexInjectionTest extends HttpServlet {
public boolean string1(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.matches("^" + pattern + "=.*$"); // BAD
return input.matches("^" + pattern + "=.*$"); // $ hasRegexInjection
}
public boolean string2(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.split(pattern).length > 0; // BAD
return input.split(pattern).length > 0; // $ hasRegexInjection
}
public boolean string3(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.replaceFirst(pattern, "").length() > 0; // BAD
return input.split(pattern, 0).length > 0; // $ hasRegexInjection
}
public boolean string4(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.replaceAll(pattern, "").length() > 0; // BAD
return input.replaceFirst(pattern, "").length() > 0; // $ hasRegexInjection
}
public boolean string5(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.replaceAll(pattern, "").length() > 0; // $ hasRegexInjection
}
public boolean pattern1(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
Pattern pt = Pattern.compile(pattern);
Pattern pt = Pattern.compile(pattern); // $ hasRegexInjection
Matcher matcher = pt.matcher(input);
return matcher.find(); // BAD
return matcher.find();
}
public boolean pattern2(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return Pattern.compile(pattern).matcher(input).matches(); // BAD
return Pattern.compile(pattern).matcher(input).matches(); // $ hasRegexInjection
}
public boolean pattern3(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return Pattern.matches(pattern, input); // BAD
return Pattern.compile(pattern, 0).matcher(input).matches(); // $ hasRegexInjection
}
public boolean pattern4(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.matches("^" + foo(pattern) + "=.*$"); // BAD
}
String foo(String str) {
return str;
return Pattern.matches(pattern, input); // $ hasRegexInjection
}
public boolean pattern5(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
// GOOD: User input is sanitized before constructing the regex
return input.matches("^" + escapeSpecialRegexChars(pattern) + "=.*$");
return input.matches("^" + foo(pattern) + "=.*$"); // $ hasRegexInjection
}
public boolean pattern6(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
escapeSpecialRegexChars(pattern);
// BAD: the pattern is not really sanitized
return input.matches("^" + pattern + "=.*$");
}
Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\]><-=!.+*?^$\\\\|]");
String escapeSpecialRegexChars(String str) {
return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0");
String foo(String str) {
return str;
}
public boolean apache1(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.removeAll(input, pattern).length() > 0; // BAD
return RegExUtils.removeAll(input, pattern).length() > 0; // $ hasRegexInjection
}
public boolean apache2(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.removeFirst(input, pattern).length() > 0; // BAD
return RegExUtils.removeFirst(input, pattern).length() > 0; // $ hasRegexInjection
}
public boolean apache3(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.removePattern(input, pattern).length() > 0; // BAD
return RegExUtils.removePattern(input, pattern).length() > 0; // $ hasRegexInjection
}
public boolean apache4(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.replaceAll(input, pattern, "").length() > 0; // BAD
return RegExUtils.replaceAll(input, pattern, "").length() > 0; // $ hasRegexInjection
}
public boolean apache5(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.replaceFirst(input, pattern, "").length() > 0; // BAD
return RegExUtils.replaceFirst(input, pattern, "").length() > 0; // $ hasRegexInjection
}
public boolean apache6(javax.servlet.http.HttpServletRequest request) {
@@ -136,13 +127,40 @@ public class RegexInjection extends HttpServlet {
String input = request.getParameter("input");
Pattern pt = (Pattern)(Object) pattern;
return RegExUtils.replaceFirst(input, pt, "").length() > 0; // GOOD, Pattern compile is the sink instead
return RegExUtils.replaceFirst(input, pt, "").length() > 0; // Safe: Pattern compile is the sink instead
}
public boolean apache7(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return RegExUtils.replacePattern(input, pattern, "").length() > 0; // BAD
return RegExUtils.replacePattern(input, pattern, "").length() > 0; // $ hasRegexInjection
}
// test `Pattern.quote` sanitizer
public boolean quoteTest(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return input.matches(Pattern.quote(pattern)); // Safe
}
// test `Pattern.LITERAL` sanitizer
public boolean literalTest(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
String input = request.getParameter("input");
return Pattern.compile(pattern, Pattern.LITERAL).matcher(input).matches(); // Safe
}
public Splitter guava1(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
return Splitter.onPattern(pattern); // $ hasRegexInjection
}
public Splitter guava2(javax.servlet.http.HttpServletRequest request) {
String pattern = request.getParameter("pattern");
// sink is `Pattern.compile`
return Splitter.on(Pattern.compile(pattern)); // $ hasRegexInjection
}
}

View File

@@ -0,0 +1,20 @@
import java
import TestUtilities.InlineExpectationsTest
import semmle.code.java.security.regexp.RegexInjectionQuery
class RegexInjectionTest extends InlineExpectationsTest {
RegexInjectionTest() { this = "RegexInjectionTest" }
override string getARelevantTag() { result = "hasRegexInjection" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasRegexInjection" and
exists(DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c |
c.hasFlowPath(source, sink)
|
location = sink.getNode().getLocation() and
element = sink.getNode().toString() and
value = ""
)
}
}

View File

@@ -1 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/guava-30.0:${testdir}/../../../stubs/servlet-api-2.4:${testdir}/../../../stubs/apache-commons-lang3-3.7