Просмотр исходного кода

fix(security): 修复XXE风险

禁用XML DTD与外部实体,加固企微回调与XMLParse解析。

Co-authored-by: Cursor <cursoragent@cursor.com>
吴树波 2 дней назад
Родитель
Сommit
2d0c50a8bd

+ 29 - 0
fs-common/src/main/java/com/fs/common/utils/security/XmlSecurityUtils.java

@@ -0,0 +1,29 @@
+package com.fs.common.utils.security;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * XML 解析安全工厂:禁用 DTD/外部实体,防止 XXE
+ */
+public final class XmlSecurityUtils {
+
+    private XmlSecurityUtils() {
+    }
+
+    /**
+     * 创建已禁用外部实体的 DocumentBuilder
+     */
+    public static DocumentBuilder newSafeDocumentBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        // 禁止 DOCTYPE,阻断绝大多数 XXE
+        dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+        dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+        dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+        dbf.setXIncludeAware(false);
+        dbf.setExpandEntityReferences(false);
+        return dbf.newDocumentBuilder();
+    }
+}

+ 3 - 3
fs-qw-api/src/main/java/com/fs/app/controller/QwController.java

@@ -3,6 +3,7 @@ package com.fs.app.controller;
 import com.fs.app.service.QwDataCallbackService;
 import com.fs.qw.domain.QwCompany;
 import com.fs.qw.mapper.QwCompanyMapper;
+import com.fs.common.utils.security.XmlSecurityUtils;
 import com.fs.qwApi.util.AesException;
 import com.fs.qwApi.util.WXBizMsgCrypt;
 import com.fs.qwApi.util.XMLParse;
@@ -13,7 +14,6 @@ import org.w3c.dom.Document;
 import org.xml.sax.InputSource;
 
 import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import java.io.StringReader;
 
 @RestController
@@ -102,8 +102,8 @@ public class QwController {
             // 加密成功
             // TODO: 解析出明文xml标签的内容进行处理
             // For example:
-            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-            DocumentBuilder db = dbf.newDocumentBuilder();
+            // 禁用 DTD/外部实体,防止 XXE(不影响正常企微明文 XML 解析)
+            DocumentBuilder db = XmlSecurityUtils.newSafeDocumentBuilder();
             StringReader sr = new StringReader(sMsg);
             InputSource is = new InputSource(sr);
             Document document = db.parse(is);

+ 7 - 0
fs-service/src/main/java/com/fs/qwApi/util/XMLParse.java

@@ -34,6 +34,13 @@ public  class XMLParse {
 		Object[] result = new Object[3];
 		try {
 			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+			// 禁用 DTD/外部实体,防止 XXE
+			dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+			dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+			dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+			dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+			dbf.setXIncludeAware(false);
+			dbf.setExpandEntityReferences(false);
 			DocumentBuilder db = dbf.newDocumentBuilder();
 			StringReader sr = new StringReader(xmltext);
 			InputSource is = new InputSource(sr);