应同时进行路径归一化校验和XML解析器安全配置:先用os.path.realpath()或Paths.get().toRealPath()解析用户路径并与白名单根目录比对前缀,再禁用DOCTYPE声明及外部实体加载。
XML解析时如何阻止../路径遍历
XML文件上传后若直接用用户输入的文件名拼接本地路径(比如读取document.dtd或外部实体),攻击者可通过../向上跳转目录,读取/etc/passwd或应用配置文件。关键不是“禁用外部实体”,而是从路径构造环节就切断遍历可能。
- 所有用户可控的文件名/路径参数必须经过
os.path.realpath()(Python)或Paths.get().toRealPath()(Java NIO)解析后,再与白名单根目录比对前缀 - 禁止用
String.replace("../", "")或正则简单过滤——....//、%2e%2e%2f、..\(Windows)仍可绕过 - 若使用
DocumentBuilder或libxml2加载XML,必须显式关闭外部实体:设置setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
Java中SAX/DOM解析器的安全配置
默认SAXParserFactory和DocumentBuilderFactory允许外部DTD和实体,这是XXE和路径遍历的共同入口。仅靠应用层校验路径不解决根本问题。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
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.setXIncludeAware(false);
-
disallow-doctype-decl直接禁止/code>,最彻底 - 若业务必须支持DOCTYPE(极少见),则需配合
EntityResolver拦截所有resolveEntity调用,返回空InputSource - 注意:Tomcat 8.5+ 默认已禁用外部实体,但Spring Boot内嵌Tomcat若覆盖了
DocumentBuilderFactorybean,仍可能回退到不安全状态
Python lxml与defusedxml的选型差异
lxml默认开启外部实体,且etree.parse()会自动加载file://协议资源;而defusedxml是专为防御XXE设计的封装层,但不处理路径拼接逻辑。