解析 XML 时的外部实体(XXE)是老问题。JDK 21 的解析器默认到底会不会读本地文件、请求远程 DTD?每个 API 的安全开关该怎么设?这篇用自己创建的测试文件与本机 HTTP 服务做防御性验证,逐个确认每个开关实际挡住了什么。
DOM 默认配置,本地文件实体 → 解析成功,文本 = "SECRET-MARKER-12345" ← 读到了本地文件 SAX 默认配置,本地文件实体 → 解析成功,文本 = "SECRET-MARKER-12345" ← 读到了本地文件 StAX 默认配置,本地文件实体 → 解析成功,文本 = "SECRET-MARKER-12345" ← 读到了本地文件 Transformer(XSLT 身份转换)默认,本地文件实体 → 解析成功,文本 = "<r>SECRET-MARKER-12345</r>" ← 读到了本地文件 DOM 默认配置,远程外部 DTD(http://127.0.0.1) → 解析成功,文本 = "REMOTE-DTD-VALUE" ← 取了远程 DTD (这一段里测试 HTTP 服务器共收到 1 次请求:['/ext.dtd'])
DOM + FEATURE_SECURE_PROCESSING(true) → SAXParseException: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD p… DOM + disallow-doctype-decl → SAXParseException: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. DOM + external-general-entities=false → 解析成功,文本 = "" DOM + setExpandEntityReferences(false) → 解析成功,文本 = "" DOM + ACCESS_EXTERNAL_DTD=""(只关 DTD) → SAXParseException: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD p… DOM + ACCESS_EXTERNAL_DTD="" + ACCESS_EXTERNAL_SCHEMA="" → SAXParseException: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD p… DOM + ACCESS_EXTERNAL_DTD="",远程 DTD → SAXParseException: External DTD: Failed to read external DTD 'ext.dtd', because 'http' access is not allowed due to restriction set by the accessExternalDTD property. DOM + external-parameter-entities=false 与 load-external-dtd=false,远程 DTD → 解析成功,文本 = "" [Fatal Error] :1:202: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD property. [Fatal Error] :1:31: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. [Fatal Error] :1:202: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD property. [Fatal Error] :1:202: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD property. [Fatal Error] :1:74: External DTD: Failed to read external DTD 'ext.dtd', because 'http' access is not allowed due to restriction set by the accessExternalDTD property. (这一段里测试 HTTP 服务器共收到 0 次请求:[])
StAX + IS_SUPPORTING_EXTERNAL_ENTITIES=false → 解析成功,文本 = "" StAX + SUPPORT_DTD=false → XMLStreamException: ParseError at [row,col]:[1,203] Message: The entity "x" was referenced, but not declared. Transformer + ACCESS_EXTERNAL_DTD=""(输入侧未限制) → TransformerException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 202; External Entity: Failed to read external document 'secret.txt', because 'file' access… Transformer + FEATURE_SECURE_PROCESSING → TransformerException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 202; External Entity: Failed to read external document 'secret.txt', because 'file' access… [Fatal Error] :1:202: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD property. [Fatal Error] :1:202: External Entity: Failed to read external document 'secret.txt', because 'file' access is not allowed due to restriction set by the accessExternalDTD property.
DOM 默认配置,10 层每层 10 倍的嵌套实体(共 10^10 个 lol) → SAXParseException: JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK. DOM + disallow-doctype-decl → SAXParseException: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. DOM + 关闭 secure processing → 解析成功,文本 = "3000000 个字符 [755 ms]" 设置 -Djdk.xml.entityExpansionLimit=100 后的小实体链 → SAXParseException: JAXP00010001: The parser has encountered more than "100" entity expansions in this document; this is the limit imposed by the JDK. [Fatal Error] :1:1: JAXP00010001: The parser has encountered more than "64000" entity expansions in this document; this is the limit imposed by the JDK. [Fatal Error] :1:31: DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true. [Fatal Error] :1:1: JAXP00010001: The parser has encountered more than "100" entity expansions in this document; this is the limit imposed by the JDK.