【JAVA XXE攻擊】微信支付官方迴應XML外部實體注入漏洞
阿新 • • 發佈:2020-12-16
官方迴應連線:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5
其中明確指出了程式碼修改的地方。
然後看到此文件後,我就改公司專案中程式碼,專案中支付時並沒有涉及到XML解析,
而是在支付後,微信回撥告知支付結果時,我這邊接受時需要解析XML。
/** * 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml資料。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map doXMLParse(String strxml) throws JDOMException, IOException { if(null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = HttpClientUtil.String2Inputstream(strxml); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if(children.isEmpty()) { v = e.getTextNormalize(); } else { v = XMLUtil.getChildrenText(children); } m.put(k, v); }
很明顯,我這個原有的程式碼中解析XML時,並沒有“DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();”,而是SAXBuilder builder = new SAXBuilder();
後來發現當使用SAXBuilder時 ,可以這樣處理以達到防止XXE攻擊。
/** * 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml資料。 * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map doXMLParse(String strxml) throws JDOMException, IOException { if(null == strxml || "".equals(strxml)) { return null; } Map m = new HashMap(); InputStream in = HttpClientUtil.String2Inputstream(strxml); SAXBuilder builder = new SAXBuilder(); // 這是優先選擇. 如果不允許DTDs (doctypes) ,幾乎可以阻止所有的XML實體攻擊 String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; builder.setFeature(FEATURE, true); FEATURE = "http://xml.org/sax/features/external-general-entities"; builder.setFeature(FEATURE, false); FEATURE = "http://xml.org/sax/features/external-parameter-entities"; builder.setFeature(FEATURE, false); FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; builder.setFeature(FEATURE, false); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while(it.hasNext()) { Element e = (Element) it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if(children.isEmpty()) { v = e.getTextNormalize(); } else { v = XMLUtil.getChildrenText(children); } m.put(k, v); } //關閉流 in.close(); return m; }
即:設定builder的feature ,
/ 這是優先選擇. 如果不允許DTDs (doctypes) ,幾乎可以阻止所有的XML實體攻擊 String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; builder.setFeature(FEATURE, true); FEATURE = "http://xml.org/sax/features/external-general-entities"; builder.setFeature(FEATURE, false); FEATURE = "http://xml.org/sax/features/external-parameter-entities"; builder.setFeature(FEATURE, false); FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; builder.setFeature(FEATURE, false);