тысячи заметок были выложены в открытый доступ,GiteeиGitHubпоискchihiro-notes
,Содержит исходные файлы заметок.md
,И PDF-версия для удобного чтения.,И да использует красивую тему,Лучший опыт чтения,Если статья полезна для вас, пожалуйста, нажмите на нее для меня.Star
~
возобновлять:Поддержка чтения статей онлайн,Классифицированы по дате выпуска.
@toc
Предварительная подготовка
2.3 Источником используемого примера кода является Enterprise WeChat-Центр разработчиков.
Документация по открытию и получению информации в Enterprise WeChat
https://developer.work.weixin.qq.com/document/10514
Предприятие Вичат Включите получение сообщений
、Проверьте действительность URL-адреса
、SHA1
、Предоставляет интерфейс Расшифровать для получения и отправки сообщений Вичат предприятиям.
、Интерфейс расчета подписи сообщения
В серверной части управления предприятием введите целевое приложение, которое необходимо настроить для получения сообщений, нажмите кнопку «Настроить прием API» в разделе «Получение сообщений», чтобы войти на страницу конфигурации.
Используемые три параметра: URL, Token и EncodingAESKey.
Эти три параметра необходимо использовать в следующем коде.
При нажатии «Сохранить» для отправки вышеуказанной информации,Предприятие Вичат отправит подтверждающее сообщение на указанный URL.,Способ отправки:GET。 После того как принимающий сервер сообщений предприятия получит запрос на проверку, ему необходимо дать правильный ответ, чтобы пройти проверку URL-адреса.
Предположим, что адрес получателя сообщения установлен на:http://api.3dept.com/
,Предприятие Вичат отправит на этот адрес следующий запрос на проверку:
Метод запроса: ПОЛУЧИТЬ Запросить адрес:
http://api.3dept.com/?msg_signature=ASDFQWEXZCVAQFASDFASDFSS×tamp=13500001234&nonce=123412323&echostr=ENCRYPT_STR
Описание параметра
параметр | должен | иллюстрировать |
---|---|---|
msg_signature | да | предприятие Вичатшифрованиезнак,msg_signature结合了предприятие填写的token、временная метка в запросе、nonceпараметр、шифрованиетело сообщения |
timestamp | да | Временная метка |
nonce | да | случайное число |
echostr | да | Зашифрованная строка. Его необходимо расшифровать, чтобы получить простой текст содержимого сообщения. После расшифровки есть четыре поля: случайное, msg_len, msg и CorpID — это простой текст содержимого сообщения. |
После того как серверная часть предприятия получит запрос, ей необходимо сделать следующее:
QYWeiXinLoginController.java
**package com.ruoyi.project.controller;
import com.ruoyi.project.tx.qyweixin.service.IQYWeiXinLoginService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/wechat/info")
public class QYWechatInfoController {
@Resource
private IQYWeiXinLoginService qyWeiXinLoginService;
/**
* Проверьте действительность URL-адреса
*
*/
@RequestMapping(value = "/verifyURLValidity", method = RequestMethod.GET)
public void verifyURLValidity(@RequestParam(value = "msg_signature", required = true) String msgSignature,
@RequestParam(value = "timestamp", required = true) String timestamp,
@RequestParam(value = "nonce", required = true) String nonce,
@RequestParam(value = "echostr", required = true) String echostr,
HttpServletResponse response) {
String msg = qyWeiXinLoginService.verifyURLValidity(msgSignature, timestamp, nonce, echostr);
try {
response.getWriter().print(msg);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
IQYWeiXinLoginService.java
**package com.ruoyi.project.tx.qyweixin.service;
public interface IQYWeiXinLoginService {
String verifyURLValidity(String msgSignature, String timestamp, String nonce, String echostr);
}
QYWeiXinLoginServiceImpl.java
**package com.ruoyi.project.tx.qyweixin.service.impl;
import com.ruoyi.project.tx.qyweixin.service.IQYWeiXinLoginService;
import com.ruoyi.project.utils.aes.AesException;
import com.ruoyi.project.utils.aes.WXBizMsgCrypt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class QYWeiXinLoginServiceImpl implements IQYWeiXinLoginService {
private static final Logger logger = LoggerFactory.getLogger(QYWeiXinLoginServiceImpl.class);
@Override
public String verifyURLValidity(String msgSignature, String timestamp, String nonce, String echostr) {
logger.info("параметр, полученный предприятием Вичат логин: msgSignature:{},timestamp:{},nonce:{},echostr:{}:",msgSignature,timestamp,nonce,echostr);
//token
String TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// encodingAESKey
String ENCODINGAES_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
//Идентификатор предприятия
String CORP_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// Проверьте запрос, проверив msg_signature. Если проверка прошла успешно, echostr будет возвращен без изменений, что указывает на успешный доступ, в противном случае доступ завершится неудачно.
String result = null;
try {
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(TOKEN, ENCODINGAES_KEY, CORP_ID);
result = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr);
} catch (AesException e) {
e.printStackTrace();
}
logger.info("----------Доступ к интерфейсу Вичат окончен ----------");
return result;
}
}
WXBizMsgCrypt.java
**/**
* Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
/**
* Для org.apache.commons.codec.binary.Base64:
* Необходимо импортировать стоечный пакет commons-codec-1.9 (или commons-codec-1.8 и другие версии).
* Официальный адрес загрузки: http://commons.apache.org/proper/commons-codec/download_codec.cgi.
*/
package com.ruoyi.project.utils.aes;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* Предоставляет интерфейс шифрования и дешифрования (строка в кодировке UTF8) для получения и отправки сообщений предприятиям.
* <ol>
* <li>ответ третьей сторонышифрованиеинформация给предприятие Вичат</li>
* <li>第三方收到предприятие Вичатсообщение отправлено,Проверьте безопасность сообщения,и обработать сообщение Расшифровать。</li>
* </ol>
* иллюстрировать:аномальныйjava.security.InvalidKeyException:illegal Key Решение по размеру
* <ol>
* <li>Скачать с официального сайтаJCEФайл политики неограниченных разрешений(JDK7скачать адрес:
* http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>
* <li>Разархивируйте после загрузки,можно увидетьlocal_policy.jarиUS_export_policy.jarа такжеreadme.txt</li>
* <li>Если установленоJRE,поставь дваjarфайл в%JRE_HOME%\lib\securityПерезаписать исходные файлы в каталоге</li>
* <li>Если установленоJDK,поставь дваjarфайл в%JDK_HOME%\jre\lib\securityПерезаписать исходный файл в каталоге</li>
* </ol>
*/
public class WXBizMsgCrypt {
static Charset CHARSET = Charset.forName("utf-8");
Base64 base64 = new Base64();
byte[] aesKey;
String token;
String receiveid;
/**
* Конструктор
* @param token Серверная часть Enterprise Вичат, токен, установленный разработчиками
* @param encodingAesKey Фон Enterprise Вичат, EncodingAESKey установлен разработчиком
* @param receiveid, Различные сценарии имеют разное значение, подробности см. в документации.
*
* @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
*/
public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
if (encodingAesKey.length() != 43) {
throw new AesException(AesException.IllegalAesKey);
}
this.token = token;
this.receiveid = receiveid;
aesKey = Base64.decodeBase64(encodingAesKey + "=");
}
// Сгенерировать 4 байта в сетевом порядке байтов.
byte[] getNetworkBytesOrder(int sourceNumber) {
byte[] orderBytes = new byte[4];
orderBytes[3] = (byte) (sourceNumber & 0xFF);
orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
return orderBytes;
}
// Восстановить 4-байтовый порядок сетевых байтов
int recoverNetworkBytesOrder(byte[] orderBytes) {
int sourceNumber = 0;
for (int i = 0; i < 4; i++) {
sourceNumber <<= 8;
sourceNumber |= orderBytes[i] & 0xff;
}
return sourceNumber;
}
// Случайно сгенерировать 16-значную строку
String getRandomStr() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 16; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* Зашифровать открытый текст.
*
* @param text Обычный текст, который необходимо зашифровать
* @return Зашифрованная строка в кодировке Base64
* @throws AesException AES-шифрование не удалось
*/
String encrypt(String randomStr, String text) throws AesException {
ByteGroup byteCollector = new ByteGroup();
byte[] randomStrBytes = randomStr.getBytes(CHARSET);
byte[] textBytes = text.getBytes(CHARSET);
byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
byte[] receiveidBytes = receiveid.getBytes(CHARSET);
// randomStr + networkBytesOrder + text + receiveid
byteCollector.addBytes(randomStrBytes);
byteCollector.addBytes(networkBytesOrder);
byteCollector.addBytes(textBytes);
byteCollector.addBytes(receiveidBytes);
// ... + pad: Используйте собственный метод заполнения для заполнения обычного текста
byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
byteCollector.addBytes(padBytes);
// Получите окончательный поток байтов, Не зашифровано
byte[] unencrypted = byteCollector.toBytes();
try {
// Установите режим шифрования на режим CBC AES.
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
// шифрование
byte[] encrypted = cipher.doFinal(unencrypted);
// Используйте BASE64 для кодирования строки после шифрования.
String base64Encrypted = base64.encodeToString(encrypted);
return base64Encrypted;
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.EncryptAESError);
}
}
/**
* Расшифруйте зашифрованный текст.
*
* @param text Зашифрованный текст, который необходимо расшифровать
* @return Расшифрованный открытый текст
* @throws AesException расшифровка aes не удалась
*/
String decrypt(String text) throws AesException {
byte[] original;
try {
// Установите режим дешифрования на режим AES CBC.
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
// Декодировать зашифрованный текст с помощью BASE64
byte[] encrypted = Base64.decodeBase64(text);
// Расшифровать
original = cipher.doFinal(encrypted);
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.DecryptAESError);
}
String xmlContent, from_receiveid;
try {
// Удалить символы заполнения
byte[] bytes = PKCS7Encoder.decode(original);
// Отдельная 16-битная случайная строка, порядок сетевых байтов и идентификатор получения.
byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
int xmlLength = recoverNetworkBytesOrder(networkOrder);
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
CHARSET);
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.IllegalBuffer);
}
// Когда полученный идентификатор отличается
if (!from_receiveid.equals(receiveid)) {
throw new AesException(AesException.ValidateCorpidError);
}
return xmlContent;
}
/**
* 将предприятие Вичат Ответ на сообщение пользователяшифрование Пакет.
* <ol>
* <li>对要сообщение отправлено进行AES-CBCшифрование</li>
* <li>Создать подпись безопасности</li>
* <li>отправит сообщениезашифрованный текстизащищенная подпись Пакет成xmlФормат</li>
* </ol>
*
* @param replyMsg Сообщение предприятия, на которое пользователь должен ответить, строка в формате xml.
* @param timeStamp Временная метка, вы можете сгенерировать ее самостоятельно или использовать временную метку параметра URL.
* @param nonce Случайная строка, вы можете сгенерировать ее самостоятельно или использовать параметр nonce URL-адреса.
*
* @return шифрование может напрямую отвечать на зашифрованные сообщения пользователя. текст,Включает msg_signature, timestamp, nonce, зашифровать строку формата XML
* @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
*/
public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
// шифрование
String encrypt = encrypt(getRandomStr(), replyMsg);
// Создать подпись безопасности
if (timeStamp == "") {
timeStamp = Long.toString(System.currentTimeMillis());
}
String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
// System.out.println("Подпись отправлена на платформу: " + signature[1].toString());
// Создать XML для отправки
String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
return result;
}
/**
* Проверьте подлинность сообщения,и получить Расшифроватьобычный текст после.
* <ol>
* <li>Используйте полученноезашифрованный текст Создать подпись безопасности,进行знак验证</li>
* <li>Если проверка пройдена,Затем извлекитеxmlвшифрованиеинформация</li>
* <li>对информация进行Расшифровать</li>
* </ol>
*
* @param msgSignature Строка подписи, соответствующая msg_signature параметра URL.
* @param timeStamp Временная метка, временная метка, соответствующая параметру URL.
* @param nonce Случайная строка, соответствующая nonce параметра URL.
* @param postData Шифрованный текст, соответствующий данным POST-запроса.
*
* @return Оригинальный текст после Расшифровать
* @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
*/
public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
throws AesException {
// Ключ, приложение для общедоступной учетной записи secret
// Извлечь зашифрованный текст
Object[] encrypt = XMLParse.extract(postData);
// Проверьте подпись безопасности
String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
// Сравните с подписью в URL на предмет равенства.
// System.out.println("Третья сторона получила подпись в URL:" + msg_sign);
// System.out.println("Сторонняя проверочная подпись:" + signature);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
// Расшифровать
String result = decrypt(encrypt[1].toString());
return result;
}
/**
* URL-адрес подтверждения
* @param msgSignature Строка подписи, соответствующая msg_signature параметра URL.
* @param timeStamp Временная метка, временная метка, соответствующая параметру URL.
* @param nonce Случайная строка, соответствующая nonce параметра URL.
* @param echoStr Случайная строка, echostr, соответствующая параметру URL.
*
* @return Расшифроватьпослеechostr
* @throws AesException Не удалось выполнить выполнение. Проверьте код ошибки и конкретную информацию об ошибке для исключения.
*/
public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
throws AesException {
String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
if (!signature.equals(msgSignature)) {
throw new AesException(AesException.ValidateSignatureError);
}
String result = decrypt(echoStr);
return result;
}
}
AesException.java
**package com.ruoyi.project.utils.aes;
/**
* добавлять Расшифроватьаномальный类
*/
public class AesException extends Exception {
public final static int OK = 0;
public final static int ValidateSignatureError = -40001;
public final static int ParseXmlError = -40002;
public final static int ComputeSignatureError = -40003;
public final static int IllegalAesKey = -40004;
public final static int ValidateCorpidError = -40005;
public final static int EncryptAESError = -40006;
public final static int DecryptAESError = -40007;
public final static int IllegalBuffer = -40008;
//public final static int EncodeBase64Error = -40009;
//public final static int DecodeBase64Error = -40010;
//public final static int GenReturnXmlError = -40011;
private int code;
private static String getMessage(int code) {
switch (code) {
case ValidateSignatureError:
return «Ошибка проверки подписи»;
case ParseXmlError:
return «Ошибка анализа XML»;
case ComputeSignatureError:
return "shaшифрование生成знак失败";
case IllegalAesKey:
return «SymmetricKey является незаконным»;
case ValidateCorpidError:
return «корпорированная проверка не удалась»;
case EncryptAESError:
return "AES-шифрование не удалось";
case DecryptAESError:
return "расшифровка aes не удалась";
case IllegalBuffer:
return «Буфер, полученный после Расшифровать, является незаконным»;
// case EncodeBase64Error:
// return "ошибка шифрования base64";
// case DecodeBase64Error:
// return "base64Расшифровать ошибку";
// case GenReturnXmlError:
// return «создание XML не удалось»;
default:
return null; // cannot be
}
}
public int getCode() {
return code;
}
AesException(int code) {
super(getMessage(code));
this.code = code;
}
}
ByteGroup.java
package com.ruoyi.project.utils.aes;
import java.util.ArrayList;
class ByteGroup {
ArrayList<Byte> byteContainer = new ArrayList<Byte>();
public byte[] toBytes() {
byte[] bytes = new byte[byteContainer.size()];
for (int i = 0; i < byteContainer.size(); i++) {
bytes[i] = byteContainer.get(i);
}
return bytes;
}
public ByteGroup addBytes(byte[] bytes) {
for (byte b : bytes) {
byteContainer.add(b);
}
return this;
}
public int size() {
return byteContainer.size();
}
}
PKCS7Encoder.java
**package com.ruoyi.project.utils.aes;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* Предоставить на основеPKCS7算法的добавлять Расшифроватьинтерфейс.
*/
class PKCS7Encoder {
static Charset CHARSET = Charset.forName("utf-8");
static int BLOCK_SIZE = 32;
/**
* Получите байты, дополняющие открытый текст.
*
* @param count Количество байтов открытого текста, которые необходимо заполнить и дополнить.
* @return Массив байтов для завершения
*/
static byte[] encode(int count) {
// Подсчитайте количество цифр для заполнения
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// Получить персонажа, используемого для заполнения позиции
char padChr = chr(amountToPad);
String tmp = new String();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
}
return tmp.getBytes(CHARSET);
}
/**
* Удалите дополнительные символы открытого текста после Расшифровать.
*
* @param decrypted Расшифроватьобычный текст после
* @return Удалите простой текст после символов заполнения.
*/
static byte[] decode(byte[] decrypted) {
int pad = (int) decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
/**
* Преобразование чисел в символы, соответствующие коду ASCII, используемые для дополнения обычного текста.
*
* @param a Числа, которые нужно преобразовать
* @return Преобразованные символы
*/
static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}
}
SHA1.java
**package com.ruoyi.project.utils.aes;
import java.security.MessageDigest;
import java.util.Arrays;
/**
* Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
/**
* SHA1 class
*
* Интерфейс вычисления подписи сообщения.
*/
public class SHA1 {
/**
* Использование алгоритма SHA1 Создать подпись безопасности
* @param token счет
* @param timestamp Временная метка
* @param nonce случайная строка
* @param encrypt зашифрованный текст
* @return защищенная подпись
* @throws AesException
*/
public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
{
try {
String[] array = new String[] { token, timestamp, nonce, encrypt };
StringBuffer sb = new StringBuffer();
// Сортировка строк
Arrays.sort(array);
for (int i = 0; i < 4; i++) {
sb.append(array[i]);
}
String str = sb.toString();
// Генерация подписи SHA1
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
throw new AesException(AesException.ComputeSignatureError);
}
}
}
XMLParse.java
**/**
* Пример кода для шифрования и расшифровки сообщений, отправляемых предприятием на серверную часть предприятия.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
package com.ruoyi.project.utils.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");
result[0] = 0;
result[1] = nodelist1.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);
}
}