应强制白名单过滤SVG:1、用XML解析器加载并禁用外部实体;2、移除script、foreignObject等高危元素;3、删除on开头事件属性及危险href值。

如果您允许用户上传SVG文件,攻击者可能通过嵌入恶意脚本或外部实体触发XSS或XXE攻击。以下是防范此类风险的具体措施:
一、服务端强制SVG内容白名单过滤
仅允许SVG规范中明确安全的元素、属性和事件处理函数,剥离所有潜在执行能力的标签与属性,从根本上阻断脚本注入路径。
1、解析上传的SVG文件为DOM树,使用XML解析器(如Python的xml.etree.ElementTree或Java的DocumentBuilder)加载并禁用外部实体解析。
2、遍历所有节点,移除包含script、foreignObject、animate、set、handler等高危元素的节点。
3、检查每个属性,删除以on开头的事件属性(如onclick、onload)、xlink:href、href(当值以javascript:或style中含expression(或url(引用外部资源的片段。
4、对保留的viewBox、fill、stroke等展示类属性进行正则校验,仅接受预设格式的值。
二、禁用XML外部实体并关闭DTD解析
XXE攻击依赖XML解析器加载外部DTD或实体定义,通过配置解析器拒绝所有外部声明,可彻底消除该攻击面。
1、在Java中使用DocumentBuilderFactory时,调用setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)并设置setFeature("http://xml.org/sax/features/external-general-entities", false)。
2、在PHP中使用libxml时,在解析前执行libxml_disable_entity_loader(true),并在simplexml_load_string()或DOMDocument::loadXML()前确保该设置生效。
3、在Node.js中使用svgson或fast-xml-parser时,显式将ignoreAttributes设为false并禁用allowDoctype与ignoreDeclaration选项,同时不启用parseNode回调中的任意代码执行逻辑。
三、转换为静态图像并剥离XML结构
将SVG彻底转化为无交互能力的栅格图像(如PNG),消除所有XML语义与可执行上下文,适用于仅需展示用途的场景。
1、使用服务端渲染工具(如Puppeteer、Resvg或Inkscape CLI)加载原始SVG,设置超时与沙箱限制,避免无限循环或内存耗尽。
2、指定输出分辨率为固定DPI(如96),裁剪至合理画布尺寸(如最大2000×2000像素),防止过大资源消耗。
3、生成PNG后,验证其二进制头为\x89PNG\r\n\x1a\n,且文件大小处于预期区间(如5KB–5MB),拒绝异常文件。
4、将生成的PNG作为最终存储文件,原SVG文件立即删除,数据库中仅保存PNG路径与元信息。
四、响应头与CSP策略协同防御
即使SVG内容被误放行,通过HTTP响应头与内容安全策略可限制其执行环境,降低XSS实际危害。
1、对所有SVG响应设置Content-Type: image/svg+xml,并附加X-Content-Type-Options: nosniff,防止浏览器MIME嗅探误判为HTML。
2、在返回SVG的HTTP头中加入X-Frame-Options: DENY与Referrer-Policy: no-referrer,切断iframe嵌套利用与Referer泄露路径。
3、若SVG需在网页中内联渲染,主页面CSP策略必须显式禁止script-src 'none',且不允许'unsafe-inline'或'unsafe-eval',同时限制img-src仅指向可信CDN域名。
五、上传前客户端轻量校验与服务端二次验证
客户端校验可快速拦截明显恶意文件,但不可替代服务端验证;两者结合形成纵深校验链。
1、前端JavaScript读取文件二进制内容,使用new Blob([file]).text()获取字符串,用正则检测是否存在、DOCTYPE、ENTITY等关键词,匹配即阻止提交。
2、提取SVG根节点
3、服务端接收后,再次解析字节流,比对SHA-256哈希值是否与前端传递的校验值一致,防止绕过前端校验的篡改请求。
4、对同一用户连续上传行为做频率限制(如5分钟内最多3次SVG上传),并记录原始文件SHA-256与解析日志,供审计追溯。










