微信支付XXE漏洞

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

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


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


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

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

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

 或者这样

或者这样

那么如何解决呢,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<Object, Object> 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<String, String> data = new HashMap<String, String>();
        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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值