微信支付XXE漏洞

某个风和日丽的下午,突然收到领导的微信截图,

微信支付XXE漏洞_第1张图片

看到后虎躯一震,没遇到过o(╯□╰)o!!!!平复后使用无所不知的度娘XXE漏洞详情


XML外部实体注入漏洞(XML External Entity Injection,简称 XXE),以下内容需要xml基础,再次不再科普。


众所周知,我们服务端获取微信支付回调结果的通知是通过读取流并转换成xml的形式,

/** 支付成功后,微信回调返回的信息 */
		String result = new String(outSteam.toByteArray(), "utf-8");
		Map map = XMLUtil.doXMLParse(result);

但此时如果别人获取了我们的回调地址,并仿造了微信的返回结果,那么他是可以获取到我们服务器的信息,如这样

微信支付XXE漏洞_第2张图片 或者这样

或者这样

微信支付XXE漏洞_第3张图片

那么如何解决呢,xxe说到底就是非法的xml,那么我们是可以在解析xml解析时,加入校验代码如下

  public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        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);

        return documentBuilderFactory.newDocumentBuilder();
    }

附上解析和校验的完整代码

/** 支付成功后,微信回调返回的信息 */
String result = new String(outSteam.toByteArray(), "utf-8");
Map map = XMLUtil.doXMLParse(result);


/**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Map doXMLParse(String strxml) throws JDOMException,IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        Map data = new HashMap();
        if(null == strxml || "".equals(strxml)) {
            return data;
        }
        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());
                }
            }
            try {
                stream.close();
            } catch (Exception ex) {
            	 logger.error(" 微信支付回调    xml  解析失败 ", ex);
            }
            return data;
        } catch (Exception ex) {
            WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strxml);
            logger.error(" 微信支付回调    xml  解析失败 ", ex);
            return data;
        }
    }



public final class WXPayXmlUtil {
    public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        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);

        return documentBuilderFactory.newDocumentBuilder();
    }

    public static Document newDocument() throws ParserConfigurationException {
        return newDocumentBuilder().newDocument();
    }
}

PS:严重吐槽下,修复了漏洞,但是登录微信商户平台后,微信仍然提示修复漏洞,不修复关闭微信支付权限云云,和微信客服沟通,回馈,不论有没有修复,都会提示修复漏洞,严重鄙视!

 

附上官方链接https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5

 

你可能感兴趣的:(后端,微信支付)