diff --git a/java/ql/lib/semmle/code/java/frameworks/owasp/Esapi.qll b/java/ql/lib/semmle/code/java/frameworks/owasp/Esapi.qll new file mode 100644 index 00000000000..19cabda7073 --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/owasp/Esapi.qll @@ -0,0 +1,40 @@ +/** Classes and predicates for reasoning about the `owasp.easpi` package. */ + +import java + +/** + * The `org.owasp.esapi.Validator` interface. + */ +class EsapiValidator extends RefType { + EsapiValidator() { this.hasQualifiedName("org.owasp.esapi", "Validator") } +} + +/** + * The methods of `org.owasp.esapi.Validator` which validate data. + */ +class EsapiIsValidMethod extends Method { + EsapiIsValidMethod() { + this.getDeclaringType() instanceof EsapiValidator and + this.hasName([ + "isValidCreditCard", "isValidDate", "isValidDirectoryPath", "isValidDouble", + "isValidFileContent", "isValidFileName", "isValidInput", "isValidInteger", + "isValidListItem", "isValidNumber", "isValidPrintable", "isValidRedirectLocation", + "isValidSafeHTML", "isValidURI" + ]) + } +} + +/** + * The methods of `org.owasp.esapi.Validator` which return validated data. + */ +class EsapiGetValidMethod extends Method { + EsapiGetValidMethod() { + this.getDeclaringType() instanceof EsapiValidator and + this.hasName([ + "getValidCreditCard", "getValidDate", "getValidDirectoryPath", "getValidDouble", + "getValidFileContent", "getValidFileName", "getValidInput", "getValidInteger", + "getValidListItem", "getValidNumber", "getValidPrintable", "getValidRedirectLocation", + "getValidSafeHTML", "getValidURI" + ]) + } +} diff --git a/java/ql/lib/semmle/code/java/security/TrustBoundaryViolationQuery.qll b/java/ql/lib/semmle/code/java/security/TrustBoundaryViolationQuery.qll index 60801fceff6..1f84f98018f 100644 --- a/java/ql/lib/semmle/code/java/security/TrustBoundaryViolationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/TrustBoundaryViolationQuery.qll @@ -2,8 +2,10 @@ import java private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.controlflow.Guards private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.FlowSources +private import semmle.code.java.frameworks.owasp.Esapi /** * A source of data that crosses a trust boundary. @@ -26,6 +28,27 @@ class TrustBoundaryViolationSink extends DataFlow::Node { abstract class TrustBoundaryValidationSanitizer extends DataFlow::Node { } +/** + * A node validated by an OWASP ESAPI validation method. + */ +private class EsapiValidatedInputSanitizer extends TrustBoundaryValidationSanitizer { + EsapiValidatedInputSanitizer() { + this = DataFlow::BarrierGuard::getABarrierNode() or + this.asExpr().(MethodAccess).getMethod() instanceof EsapiGetValidMethod + } +} + +/** + * Holds if `g` is a guard that checks that `e` is valid data according to an OWASP ESAPI validation method. + */ +private predicate esapiIsValidData(Guard g, Expr e, boolean branch) { + branch = true and + exists(MethodAccess ma | ma.getMethod() instanceof EsapiIsValidMethod | + g = ma and + e = ma.getArgument(1) + ) +} + /** * Taint tracking for data that crosses a trust boundary. */ diff --git a/java/ql/test/query-tests/security/CWE-501/TrustBoundaryViolations.java b/java/ql/test/query-tests/security/CWE-501/TrustBoundaryViolations.java index 5bef7e087d2..9f9be44c972 100644 --- a/java/ql/test/query-tests/security/CWE-501/TrustBoundaryViolations.java +++ b/java/ql/test/query-tests/security/CWE-501/TrustBoundaryViolations.java @@ -2,11 +2,34 @@ import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.owasp.esapi.Validator; public class TrustBoundaryViolations extends HttpServlet { + Validator validator; + public void doGet(HttpServletRequest request, HttpServletResponse response) { String input = request.getParameter("input"); + // BAD: The input is written to the response without being sanitized. request.getSession().setAttribute("input", input); // $ hasTaintFlow + + String input2 = request.getParameter("input2"); + + try { + String sanitized = validator.getValidInput("HTTP parameter", input2, "HTTPParameterValue", 100, false); + // GOOD: The input is sanitized before being written to the response. + request.getSession().setAttribute("input2", sanitized); + + } catch (Exception e) { + } + + try { + String input3 = request.getParameter("input3"); + if (validator.isValidInput("HTTP parameter", input3, "HTTPParameterValue", 100, false)) { + // GOOD: The input is sanitized before being written to the response. + request.getSession().setAttribute("input3", input3); + } + } catch (Exception e) { + } } }