这是我尝试用 PHP 构建一个像样的 SVG 清理器。这项工作很大程度上借鉴了 DOMPurify。
可以通过 composer 引入 enshrined/svg-sanitize,或者下载仓库并以传统方式引入!
使用起来相当简单。创建一个 enshrined\svgSanitize\Sanitizer 的新实例,然后在传入你未清理的 SVG/XML 时调用 sanitize
基本示例
use enshrined\svgSanitize\Sanitizer;
// Create a new sanitizer instance
$sanitizer = new Sanitizer();
// Load the dirty svg
$dirtySVG = file_get_contents('filthy.svg');
// Pass it to the sanitizer and get it back clean
$cleanSVG = $sanitizer->sanitize($dirtySVG);
// Now do what you want with your clean SVG/XML data
这将返回一个经过清理的 SVG/XML 字符串,如果 XML 解析失败(通常是由于文件格式错误),则返回布尔值 false。
对于不会交给 XML 解析器的输入,它也会返回 false:
<svg> 位于 SVG 以外的命名空间中getXmlIssues() 会说明原因。
你可以分别使用 Sanitizer::setAllowedTags 和 Sanitizer::setAllowedAttrs 方法传入自己的标签和属性白名单。
这些方法要求你实现 enshrined\svgSanitize\data\TagInterface 或 enshrined\svgSanitize\data\AttributeInterface。
<use> 默认被允许,但受引用可扩展范围(useThreshold())和嵌套深度(setUseNestingLimit())的限制。如果你不需要它,例如因为你将不受信任的 SVG 内联到页面中,请将 use 从标签允许列表中移除,以彻底消除这一整块攻击面。
你可以选择移除引用远程文件的属性,这会阻止 HTTP 泄露,但会给清理器增加额外开销。
此选项默认为 false,设为 true 以移除引用。
$sanitizer->removeRemoteReferences(true);
启用后,远程引用也会从 <style> 元素内的 CSS 以及属性中的 CSS(url()、@import、image-set() 以及以远程 URL 开头的带引号字符串)中剥离。srcset 属性会被整体移除,因为它包含一组 URL。此 CSS 处理是尽力而为的:它并非完整的 CSS 解析器。请将其视为纵深防御而非保证,并在嵌入 SVG 的位置隔离不受信任的 CSS。
注意:如果 <style> 元素或 style 属性包含被剥离的远程引用,则同一块中的任何 CSS 转义序列都会在输出中被规范化(解码)。这在语义上是相同的 CSS,但会重写作者手写的转义序列。
你可以使用 getXmlIssues() 方法返回清理过程中发生的问题数组。
这对于记录日志或向用户反馈 SVG 被拒绝的原因可能很有用。
$issues = $sanitizer->getXmlIssues();
该列表最多包含 1,000 条问题。如果超过此数量,最后一条会说明有多少条被省略。
你可以通过调用 $sanitizer->minify(true); 来压缩 XML 输出。
有一个可用的演示位于:http://svg.enshrined.co.uk/
我刚刚发布了一个包含此代码的 WordPress 插件,以便你可以清理 WordPress 上传内容。它可从 WordPress 插件目录获取:https://wordpress.org/plugins/safe-svg/
Michael Potter 好心地为此库创建了一个 Drupal 模块,可在以下地址获取:https://www.drupal.org/project/svg_sanitizer
此 SVG 清理库在 TYPO3 v9 及更高版本的核心中默认使用。 有关详细信息,请参阅相应的变更日志条目。
你可以通过在此软件包的根目录下运行 vendor/bin/phpunit 来运行这些测试。
得益于 gudmdharalds 的工作,现在有一个可通过 CLI 使用的独立扫描器。
任何错误都将以 JSON 格式输出。示例请参见该 PR。
使用方法如下:php svg-scanner.php ~/svgs/myfile.svg
对 SVG/XML 进行更广泛的测试会很好,我会尽快尝试添加这些测试。如果你愿意替我完成,请尽管去做并提交 PR!