/**
|
* 对企业微信发送给企业后台的消息加解密示例代码.
|
*
|
* @copyright Copyright (c) 1998-2014 Tencent Inc.
|
*/
|
|
// ------------------------------------------------------------------------
|
|
package com.qq.weixin.mp.aes;
|
|
import java.io.StringReader;
|
|
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
import org.w3c.dom.Document;
|
import org.w3c.dom.Element;
|
import org.w3c.dom.NodeList;
|
import org.xml.sax.InputSource;
|
|
/**
|
* XMLParse class
|
*
|
* 提供提取消息格式中的密文及生成回复消息格式的接口.
|
*/
|
class XMLParse {
|
|
/**
|
* 提取出xml数据包中的加密消息
|
* @param xmltext 待提取的xml字符串
|
* @return 提取出的加密消息字符串
|
* @throws AesException
|
*/
|
public static Object[] extract(String xmltext) throws AesException {
|
Object[] result = new Object[3];
|
try {
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
String FEATURE = null;
|
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
|
// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
|
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
|
dbf.setFeature(FEATURE, true);
|
|
// If you can't completely disable DTDs, then at least do the following:
|
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
|
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
|
// JDK7+ - http://xml.org/sax/features/external-general-entities
|
FEATURE = "http://xml.org/sax/features/external-general-entities";
|
dbf.setFeature(FEATURE, false);
|
|
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
|
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
|
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
|
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
|
dbf.setFeature(FEATURE, false);
|
|
// Disable external DTDs as well
|
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
dbf.setFeature(FEATURE, false);
|
|
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
|
dbf.setXIncludeAware(false);
|
dbf.setExpandEntityReferences(false);
|
|
// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then
|
// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
|
// (http://cwe.mitre.org/data/definitions/918.html) and denial
|
// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
|
|
// remaining parser logic
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
StringReader sr = new StringReader(xmltext);
|
InputSource is = new InputSource(sr);
|
Document document = db.parse(is);
|
|
Element root = document.getDocumentElement();
|
NodeList nodelist1 = root.getElementsByTagName("Encrypt");
|
NodeList nodelist2 = root.getElementsByTagName("ToUserName");
|
result[0] = 0;
|
result[1] = nodelist1.item(0).getTextContent();
|
result[2] = nodelist2.item(0).getTextContent();
|
return result;
|
} catch (Exception e) {
|
e.printStackTrace();
|
throw new AesException(AesException.ParseXmlError);
|
}
|
}
|
|
/**
|
* 生成xml消息
|
* @param encrypt 加密后的消息密文
|
* @param signature 安全签名
|
* @param timestamp 时间戳
|
* @param nonce 随机字符串
|
* @return 生成的xml字符串
|
*/
|
public static String generate(String encrypt, String signature, String timestamp, String nonce) {
|
|
String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
|
+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
|
+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";
|
return String.format(format, encrypt, signature, timestamp, nonce);
|
|
}
|
}
|