diff --git a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.qhelp b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.qhelp index 77311698f44..f0d4129f561 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.qhelp @@ -10,7 +10,7 @@ Even though the signatures for methods in a servlet include throws IOExcep

-Handle method calls that throw IOExceptions and/or RuntimeExceptions and display custom error messages without stack traces and sensitive information. +Handle method calls that throw IOExceptions and/or RuntimeExceptions and display custom error messages without stack traces and sensitive information, or configure an error-page in web.xml to display a generic user-friendly message for any uncaught exception.

diff --git a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql index b6db6ebcf4a..e8381b3d752 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-600/UncaughtServletException.ql @@ -11,6 +11,7 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking import semmle.code.java.frameworks.Servlets +import semmle.code.xml.WebXML import DataFlow::PathGraph /** The type `java.io.IOException`. */ @@ -44,6 +45,11 @@ private predicate isServletMethod(Callable c) { ) } +/** Holds if `web.xml` has an error page configured. */ +private predicate hasErrorPage() { + exists(WebErrorPage wep | wep.getPageLocation().getValue() != "") +} + /** Sink of uncaught IO exceptions or runtime exceptions since other exception types must be explicitly caught. */ class UncaughtServletExceptionSink extends DataFlow::ExprNode { UncaughtServletExceptionSink() { @@ -74,6 +80,6 @@ class UncaughtServletExceptionConfiguration extends TaintTracking::Configuration } from DataFlow::PathNode source, DataFlow::PathNode sink, UncaughtServletExceptionConfiguration c -where c.hasFlowPath(source, sink) +where c.hasFlowPath(source, sink) and not hasErrorPage() select sink.getNode(), source, sink, "$@ flows to here and can throw uncaught exception.", source.getNode(), "User-provided value" diff --git a/java/ql/src/semmle/code/xml/WebXML.qll b/java/ql/src/semmle/code/xml/WebXML.qll index e383ffc6617..306f908afd5 100644 --- a/java/ql/src/semmle/code/xml/WebXML.qll +++ b/java/ql/src/semmle/code/xml/WebXML.qll @@ -130,3 +130,40 @@ class WebListenerClass extends WebXMLElement { */ Class getClass() { result.getQualifiedName() = getValue() } } + +/** + * An `` element in a `web.xml` file. + */ +class WebErrorPage extends WebXMLElement { + WebErrorPage() { this.getName() = "error-page" } + + /** + * Gets the `` element of this ``. + */ + WebErrorPageType getPageType() { result = getAChild() } + + /** + * Gets the `` element of this ``. + */ + WebErrorPageLocation getPageLocation() { result = getAChild() } +} + +/** + * An `` element in a `web.xml` file, nested under an `` element. + */ +class WebErrorPageType extends WebXMLElement { + WebErrorPageType() { + getName() = "exception-type" and + getParent() instanceof WebErrorPage + } +} + +/** + * A `` element in a `web.xml` file, nested under an `` element. + */ +class WebErrorPageLocation extends WebXMLElement { + WebErrorPageLocation() { + getName() = "location" and + getParent() instanceof WebErrorPage + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-600/web.xml b/java/ql/test/experimental/query-tests/security/CWE-600/web.xml new file mode 100644 index 00000000000..ddf5bfaccf3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-600/web.xml @@ -0,0 +1,17 @@ + + + + myapp + + + index.jsp + index.xhtml + + + + \ No newline at end of file