diff --git a/java/ql/src/Security/CWE/CWE-643/XPathInjection.java b/java/ql/src/Security/CWE/CWE-643/XPathInjection.java index 95a38a5a7ac..093ac32fa6a 100644 --- a/java/ql/src/Security/CWE/CWE-643/XPathInjection.java +++ b/java/ql/src/Security/CWE/CWE-643/XPathInjection.java @@ -58,9 +58,19 @@ try { // Bad Dom4j org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader(); org.dom4j.Document document = reader.read(new InputSource(new StringReader(xmlStr))); - isExist = document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']").hasContent(); + isExist = document.selectSingleNode("/users/user[@name='" + user + "' and @pass='" + pass + "']") != null; // or document.selectNodes System.out.println(isExist); + + // Good Dom4j + org.jaxen.SimpleVariableContext svc = new org.jaxen.SimpleVariableContext(); + svc.setVariableValue("user", user); + svc.setVariableValue("pass", pass); + String xpathString = "/users/user[@name=$user and @pass=$pass]"; + org.dom4j.XPath safeXPath = document.createXPath(xpathString); + safeXPath.setVariableContext(svc); + isExist = safeXPath.selectSingleNode(document) != null; + System.out.println(isExist); } } catch (ParserConfigurationException e) { diff --git a/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.java b/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.java index 62b547a2227..88aeca73b78 100644 --- a/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.java +++ b/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.java @@ -110,12 +110,12 @@ public class XPathInjectionTest { String expression4 = "/users/user[@name=$user and @pass=$pass]"; xpath.setXPathVariableResolver(v -> { switch (v.getLocalPart()) { - case "user": - return user; - case "pass": - return pass; - default: - throw new IllegalArgumentException(); + case "user": + return user; + case "pass": + return pass; + default: + throw new IllegalArgumentException(); } }); xpath.evaluate(expression4, doc, XPathConstants.BOOLEAN); // Safe @@ -154,5 +154,13 @@ public class XPathInjectionTest { Namespace namespace = new Namespace("prefix", "http://some.uri.io"); namespace.createPattern("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection namespace.createXPathFilter("/users/user[@name='" + user + "' and @pass='" + pass + "']"); // $hasXPathInjection + + org.jaxen.SimpleVariableContext svc = new org.jaxen.SimpleVariableContext(); + svc.setVariableValue("user", user); + svc.setVariableValue("pass", pass); + String xpathString = "/users/user[@name=$user and @pass=$pass]"; + org.dom4j.XPath safeXPath = document.createXPath(xpathString); // Safe + safeXPath.setVariableContext(svc); + safeXPath.selectSingleNode(document); // Safe } } diff --git a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/XPath.java b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/XPath.java index eec983b5bc7..64147c75a13 100644 --- a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/XPath.java +++ b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/XPath.java @@ -45,6 +45,7 @@ public interface XPath extends NodeFilter { void setNamespaceURIs(Map map); + void setVariableContext(org.jaxen.VariableContext variableContext); } /* diff --git a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/xpath/DefaultXPath.java b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/xpath/DefaultXPath.java index 95b0bdac499..fc7e32ed616 100644 --- a/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/xpath/DefaultXPath.java +++ b/java/ql/test/stubs/dom4j-2.1.1/org/dom4j/xpath/DefaultXPath.java @@ -91,6 +91,10 @@ public class DefaultXPath implements org.dom4j.XPath, Serializable { public void setNamespaceURIs(Map map) { } + @Override + public void setVariableContext(org.jaxen.VariableContext variableContext) { + } + } /* diff --git a/java/ql/test/stubs/jaxen-1.2.0/org/jaxen/SimpleVariableContext.java b/java/ql/test/stubs/jaxen-1.2.0/org/jaxen/SimpleVariableContext.java new file mode 100644 index 00000000000..5e34f7d92a3 --- /dev/null +++ b/java/ql/test/stubs/jaxen-1.2.0/org/jaxen/SimpleVariableContext.java @@ -0,0 +1,66 @@ +/* + * $Header$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * + * Copyright 2000-2002 bob mcwhirter & James Strachan. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the Jaxen Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ==================================================================== + * This software consists of voluntary contributions made by many + * individuals on behalf of the Jaxen Project and was originally + * created by bob mcwhirter and + * James Strachan . For more information on the + * Jaxen Project, please see . + * + * $Id$ + */ + +package org.jaxen; + +import java.io.Serializable; + +public class SimpleVariableContext implements VariableContext, Serializable { + public SimpleVariableContext() { + } + + public void setVariableValue(String namespaceURI, String localName, Object value) { + } + + public void setVariableValue(String localName, Object value) { + } + + public Object getVariableValue(String namespaceURI, String prefix, String localName) { + return null; + } + +}