22import java .io .StringReader ;
33
44import javax .servlet .http .HttpServletRequest ;
5+ import javax .xml .namespace .QName ;
56import javax .xml .parsers .DocumentBuilder ;
67import javax .xml .parsers .DocumentBuilderFactory ;
78import javax .xml .xpath .XPath ;
89import javax .xml .xpath .XPathConstants ;
910import javax .xml .xpath .XPathExpression ;
11+ import javax .xml .xpath .XPathExpressionException ;
1012import javax .xml .xpath .XPathFactory ;
1113
1214import org .w3c .dom .Document ;
1315import org .xml .sax .InputSource ;
1416
1517public class A {
18+ private static abstract class XPathImplStub implements XPath {
19+ public static XPathImplStub getInstance () {
20+ return null ;
21+ }
22+
23+ @ Override
24+ public XPathExpression compile (String expression ) throws XPathExpressionException {
25+ return null ;
26+ }
27+
28+ @ Override
29+ public Object evaluate (String expression , Object item , QName returnType ) throws XPathExpressionException {
30+ return null ;
31+ }
32+
33+ @ Override
34+ public String evaluate (String expression , Object item ) throws XPathExpressionException {
35+ return null ;
36+ }
37+
38+ @ Override
39+ public Object evaluate (String expression , InputSource source , QName returnType )
40+ throws XPathExpressionException {
41+ return null ;
42+ }
43+
44+ @ Override
45+ public String evaluate (String expression , InputSource source ) throws XPathExpressionException {
46+ return null ;
47+ }
48+
49+ }
50+
1651 public void handle (HttpServletRequest request ) throws Exception {
1752 final String xmlStr = "<users>" + " <user name=\" aaa\" pass=\" pass1\" ></user>"
1853 + " <user name=\" bbb\" pass=\" pass2\" ></user>" + "</users>" ;
1954 DocumentBuilderFactory domFactory = DocumentBuilderFactory .newInstance ();
2055 domFactory .setNamespaceAware (true );
2156 DocumentBuilder builder = domFactory .newDocumentBuilder ();
22- Document doc = builder .parse (new InputSource (new StringReader (xmlStr )));
57+ InputSource xmlSource = new InputSource (new StringReader (xmlStr ));
58+ Document doc = builder .parse (xmlSource );
2359
2460 XPathFactory factory = XPathFactory .newInstance ();
2561 XPath xpath = factory .newXPath ();
62+ XPathImplStub xpathStub = XPathImplStub .getInstance ();
2663
2764 // Injectable data
2865 String user = request .getParameter ("user" );
@@ -31,9 +68,13 @@ public void handle(HttpServletRequest request) throws Exception {
3168 // Bad expression
3269 String expression1 = "/users/user[@name='" + user + "' and @pass='" + pass + "']" ;
3370 xpath .evaluate (expression1 , doc , XPathConstants .BOOLEAN ); // $hasXPathInjection
71+ xpathStub .evaluate (expression1 , doc , XPathConstants .BOOLEAN ); // $hasXPathInjection
72+ xpath .evaluateExpression (expression1 , xmlSource ); // $hasXPathInjection
73+ xpathStub .evaluateExpression (expression1 , xmlSource ); // $hasXPathInjection
3474
3575 // Bad expression
3676 XPathExpression expression2 = xpath .compile ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
77+ xpathStub .compile ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
3778 expression2 .evaluate (doc , XPathConstants .BOOLEAN );
3879
3980 // Bad expression
@@ -44,6 +85,7 @@ public void handle(HttpServletRequest request) throws Exception {
4485 sb .append ("']" );
4586 String query = sb .toString ();
4687 XPathExpression expression3 = xpath .compile (query ); // $hasXPathInjection
88+ xpathStub .compile (query ); // $hasXPathInjection
4789 expression3 .evaluate (doc , XPathConstants .BOOLEAN );
4890
4991 // Good expression
@@ -63,9 +105,14 @@ public void handle(HttpServletRequest request) throws Exception {
63105 // Bad Dom4j
64106 org .dom4j .io .SAXReader reader = new org .dom4j .io .SAXReader ();
65107 org .dom4j .Document document = reader .read (new ByteArrayInputStream (xmlStr .getBytes ()));
66- document .selectSingleNode ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ) // $hasXPathInjection
67- .hasContent ();
108+ document .selectObject ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
68109 document .selectNodes ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
110+ document .selectNodes ("/users/user[@name='test']" , "/users/user[@pass='" + pass + "']" ); // Safe-ish
111+ document .selectSingleNode ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
112+ document .valueOf ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
113+ document .numberValueOf ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
114+ document .matches ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
115+ document .createXPath ("/users/user[@name='" + user + "' and @pass='" + pass + "']" ); // $hasXPathInjection
69116 }
70117 }
71118}
0 commit comments