防止XXE攻击:XML解析存在的安全问题指引

描述

XML 解析器无法预防和限制外部实体进行解析,这会使解析器暴露在 XML External Entities 攻击之下。
XML组件默认没有禁用外部实体引用,XML 实体可动态包含来自给定资源的数据。当使用用户的输入作为文档的一部分进行动态构建XML时,XML 解析器可以访问由用户输入的 URI 所指定的资源,因此可能导致读取任意文件;执行系统命令;探测内网端口;攻击内网网站等危害。

案例图解


外界攻击者通过模拟回调通知,在回调通知中引入不安全的XML,商户服务器上执行系统命令。

修复方法

XXE漏洞需要您在回调处理代码里面解析XML之前,加入禁用实体解析的代码,不同语言设置的内容不同,下面提供了几种主流开发语言的设置指引(您可以根据关键字找到xml解析组件采取对应方法升级):

【JAVA】

1. 读取
  • DocumentBuilderFactory
/**
 * 注意:
 * - setFeature() 需要在 newDocumentBuilder() 之前才能够生效
 * - 当 setFeature 报错时,记得设置 System.setProperty
 **/

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; // catching unsupported features

// 当出现 javax.xml.parsers.DocumentBuilderFactory.setFeature(Ljava/lang/String;Z)V 错误时,
// 需要加入以下代码,报错原因:https://blog.csdn.net/u011479200/article/details/78044824
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = "";
try {

    // 方式一:完全禁止DTD,如果传入文档包含DOCTYPE声明,则抛出错误。
    FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
    dbf.setFeature(FEATURE, true);

    
    // 方式二:如果出于某种原因需要支持内联DOCTYPE,那么确保以下实体设置被禁用(需要JDK7+),
    //        并注意防范[SSRF攻击](http://cwe.mitre.org/data/definitions/918.html)
    //        和拒绝服务攻击(比如十亿次`lol`或通过`jar:`进行解压炸弹)。
    FEATURE = "http://xml.org/sax/features/external-general-entities";
    dbf.setFeature(FEATURE, false); // 不包括外部一般实体。
    FEATURE = "http://xml.org/sax/features/external-parameter-entities";
    dbf.setFeature(FEATURE, false); // 不包含外部参数实体或外部DTD子集。
    FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
    dbf.setFeature(FEATURE, false); // 忽略外部DTD
    dbf.setXIncludeAware(false);
    dbf.setExpandEntityReferences(false);

} catch (ParserConfigurationException e) {
    logger.info("ParserConfigurationException was thrown. The feature '" +
    FEATURE + "' is probably not supported by your XML processor."); // setFeature失败
} catch (SAXException e) {
    logger.warning("DOCTYPE被传递到XML文档中"); // 在Apache上,当禁用DOCTYPE时会抛出这个错误
} catch (IOException e) {
    logger.error("IOException occurred, XXE may still possible: " + e.getMessage()); // 指向一个不存在的文件
}

DocumentBuilder safebuilder = dbf.newDocumentBuilder();
  • SAXReader
SAXReader sax = new SAXReader();
// 需加入下面这句进行防护
sax.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Document doc = sax.read(XMLFILE);
Element root = doc.getRootElement();
List<Element> list = root.elements();

2. 输出/转换
  • 要保护 TransformerFactory,应设置下列功能
TransformerFactory transFact =TransformerFactory.newInstance();

transFact.setFeature(XMLConstants.ACCESS_EXTERNAL_DTD,false);
// 如果使用的是java 8,上面一句需要改为:
// transFact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
// 原因参考:https://stackoverflow.com/questions/27128578/set-feature-accessexternaldtd-in-transformerfactory

Transformer trans =transFact.newTransformer(xsltSource);
trans.transform(xmlSource, result);
  • 或者使用安全配置的 XMLReader 来设置转换源
XMLReader reader =XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/external-general-entities",false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities",false);
Source xmlSource = new SAXSource(reader,new InputSource(new FileInputStream(xmlFile)));
Source xsltSource = new SAXSource(reader,new InputSource(new FileInputStream(xsltFile)));
Result result = newStreamResult(System.out);
TransformerFactory transFact =TransformerFactory.newInstance();
Transformer trans =transFact.newTransformer(xsltSource);
trans.transform(xmlSource, result);

3. XPath查询防护
// 若需要使用XPath进行查询,请使用ESAPI对用户输入进行转义。
ESAPI.encoder().encodeForXPath(xpath);

参考链接:XML实体注入风险


【PHP】 解析XML代码前加入:

libxml_disable_entity_loader(true); //关键代码
$xml = simplexml_load_string($xmlContent);

【.Net】

XmlDocument doc= new XmlDocument();
doc.XmlResolver = null;//关键代码

【ASP】

Set xmldom = Server.CreateObject("MSXML2.DOMDocument")
xmldom.resolveExternals = false  '关键代码

【Python】

from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

【c/c++(常用库为libxml2 libxerces-c)】 【libxml2】
确保关闭配置选项:XML_PARSE_NOENT 和 XML_PARSE_DTDLOAD
2.9版本以上已修复XXE


【Coldfusion/lucee和node.js】
请更新到库的最新版本


【libxerces-c】:
如果用的是XercesDOMParser:

XercesDOMParser *parser = new XercesDOMParser;
parser->setCreateEntityReferenceNodes(false);

如果是用SAXParser:

SAXParser* parser = new SAXParser;
parser->setDisableDefaultEntityResolution(true);

如果是用SAX2XMLReader:

SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
parser->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);

参考文档:【微信支付XML安全实践】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342