1. 程式人生 > >微信支付XXE漏洞修復解決辦法

微信支付XXE漏洞修復解決辦法

@tz

根據微信官方回覆訊息

1、您更新的只是官方SDK的部分程式碼,沒有完全更新,或者在SDK外還使用了XML的解析沒有防XXE

2、您可能有多個回撥地址,而你只修復了其中一個

3、您可能有多個伺服器,你只發布了其中一臺或者修改了沒有正式釋出

4、實際做xml解析的不是修改的地方

5、xml解析器和httpclient存在多個版本,有衝突,pom.xml可以檢視jar版本號。

修改過程

public final class WXPayXmlUtil {
    public static DocumentBuilder newDocumentBuilder
(){ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = null; try { documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities"
, false); documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING
, true); documentBuilderFactory.setXIncludeAware(false); documentBuilderFactory.setExpandEntityReferences(false); documentBuilder = documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); } return documentBuilder; } public static Document newDocument() { return newDocumentBuilder().newDocument(); }
/**
	 * 解析微信發來的請求(XML)
	 * 
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
		
		// 將解析結果儲存在HashMap中
		Map<String, String> data = new HashMap<String, String>();
		try {
            DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
            InputStream stream = request.getInputStream();
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            stream.close();
        } catch (Exception ex) {
        	System.out.println("Invalid XML, can not convert to map. Error message: {}.XML content: {}"+ ex.getMessage());
        }
		return data;
	}
/**
     * XML格式字串轉換為Map
     *
     * @param strXML XML字串
     * @return XML資料轉換後的Map
     * @throws Exception
     */
    public static Map<String, Object> parseXml2Map(String strXML) {
    	Map<String, Object> data = new HashMap<String, Object>();
        try {
            DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();
            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
            doc.getDocumentElement().normalize();
            NodeList nodeList = doc.getDocumentElement().getChildNodes();
            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
                Node node = nodeList.item(idx);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
                    data.put(element.getNodeName(), element.getTextContent());
                }
            }
            stream.close();
        } catch (Exception ex) {
        	System.out.println("Invalid XML, can not convert to map. Error message: {}.XML content: {}"+ ex.getMessage()+ strXML);
        	System.out.println(ex.getMessage());
        	System.out.println(strXML);
        }
		return data;
    }
/**
     * 將Map轉換為XML格式的字串
     *
     * @param data Map型別資料
     * @param rootElement 檔案型別
     * @return XML格式的字串
     * @throws Exception
     */
    public static String parseMap2XML(Map<String, Object> data,String rootElement) {
        org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
        org.w3c.dom.Element root = document.createElement(rootElement);
        document.appendChild(root);
        for (String key: data.keySet()) {
        	String value = String.valueOf(data.get(key));
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = null;
        StringWriter writer = null;
        String output  = null;
		try {
			transformer = tf.newTransformer();
			DOMSource source = new DOMSource(document);
	        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
	        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
	        writer = new StringWriter();
	        StreamResult result = new StreamResult(writer);
			transformer.transform(source, result);
			output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
			writer.close();
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}catch (IOException e) {
			e.printStackTrace();
		}
        return output;
    }

專案使用部分SDK,直接修改需要對XML轉換處理根據SDK更改成自己需要的。僅供參考,目前官方技術人員提示已經修復完成。