使用PHP消毒SVG



我使用d3.js时即将创建图表。这些图表是根据身份验证的用户的选择动态生成的。一旦生成这些图表,用户就可以选择下载生成的SVG作为PNG或PDF。

当前工作流程如下:

// JAVASC
// get the element containing generated SVG
var svg = document.getElementById("chart-container");
// Extract the data as SVG text string
var svg_xml = (new XMLSerializer).serializeToString(svg);
// Submit the <FORM> to the server.
var form = document.getElementById("svgform");
form['output_format'].value = output_format;  // can be either "pdf" or "png"
form['data'].value = svg_xml ;
form.submit();

表单元素是隐藏的表单,用于发布数据:

<form id="svgform" method="post" action="conversion.php">
  <input type="hidden" id="output_format" name="output_format" value="">
  <input type="hidden" id="data" name="data" value="">
</form>

PHP文件将提供的SVG数据保存为临时文件:

// check for valid session, etc - omitted for brevity 
$xmldat = $_POST['data'];  // serialized XML representing the SVG element
if(simplexml_load_string($xmldat)===FALSE) { die; } // reject invalid XML  
$fileformat = $_POST['output_format'];  // chosen format for output;  PNG or PDF
if ($fileformat != "pdf" && $fileformat != "png" ){ die; } // limited options for format
$fileformat = escapeshellarg($fileformat); // escape shell arguments that might have snuck in
// generate temporary file names with tempnam() - omitted for brevity
$handle = fopen($infile, "w");
fwrite($handle, $xmldat);
fclose($handle);

运行一个转换实用程序,该实用程序读取临时文件($ infile),并在指定的$ fileformat(pdf或png)中创建一个新文件($ outfile)。然后将结果的新文件返回到浏览器,并删除临时文件:

// headers etc generated - omitted for brevity
readfile($outfile);
unlink($infile);  // delete temporary infile  
unlink($outfile);  // delete temporary outfile  

我已经研究了使用JavaScript(Canvg(),然后是Todataurl,然后是Document.Write)将SVG转换为PNG,并可以将其用于生成PNG,但不允许转换为PDF。p> so:在将其写入文件之前,我如何才能最好地对提供给conversion.php的SVG数据进行过滤或过滤?SVG消毒的当前状态是什么?PHP中有什么可用?我是否应该采用基于白名单的方法来消毒提供给conversion.php的SVG数据,还是有更好的方法?

(我不知道XSLT,尽管我可以尝试学习;我希望尽可能地将消毒保留在PHP中。使用Windows Server 2008,因此任何使用外部工具的解决方案都需要在其中可用生态系统。)

您需要使用XML Parser Whitelist对SVG进行消毒。

由于SVG已经有多种执行代码的方法,并且将来的扩展可能会添加其他方法,因此您根本无法将"已知危险"构造黑名单。只要您正确处理所有XML角案例(例如XSLT样式表,实体扩展,外部实体参考),白名单的安全元素和属性确实可以工作。

示例实现:https://github.com/alnorris/svg-sanitizer/blob/master/svgsanitizer.php(MIT许可)或https://github.com/darylldoyle/svg-sanitizer(GPL V2许可证)

选择要支持的功能时必须考虑的有关攻击向量的更多信息:

  • https://phabricator.wikimedia.org/t85850(base64编码零件)
  • https://www.slideshare.net/x00mario/the-image-that-called-me(执行代码的不同方法)
  • https://www.blackhat.com/docs/us-14/materials/us-14-degraaf-svg-exploiting-browsers-browsers-without-image-image-parsing-parsing-parsing-bugs.pdf(嵌入html html html html svg,svg,svg,svg can can can做几乎所有 xml文件都可以做 html文件可以做的任何事情,使用 <object>内部的svg允许从svg内部执行js在父级文档中)
  • ) )
  • https://bjornjornjohansen.no/svg-in-wordpress(过滤SVG足够困难,即使WordPress仍然对用户提交的SVG文件也没有一个很好的解决方案)
  • http://html5sec.org/?svg(通过滥用不同的API来列出了一些已知的SVG攻击列表)
  • https://security.stackexchange.com/questions/26264
  • https://blobfolio.com/2017/03/when-a-stranger-calls-calls-sanitizing-svgs/(编码东西的不同方法,巧妙地使用whitespace来避免检测,xml技巧)

我正在与XML和PHP一起工作,但我不确定您的问题。请把它作为一个想法/建议,而不是更多。

单纯词使用libxml加载XML内容。http://www.php.net/manual/en/simplexml.requirements.php

您可以使用:

禁用外部实体
libxml_disable_entity_loader (TRUE)

http://www.php.net/manual/en/function.libxml-disable-entity-loader.php

在用单纯>加载文件之前。

然后您可以对SVG模式进行验证

http://us3.php.net/manual/en/domdocument.schemavalidate.php或者http://us3.php.net/manual/en/domdocument.validate.php

我唯一的问题是SVG可能包含脚本元素。http://www.w3.org/tr/svg/script.html#scriptlement

这里有1.1 DTD的信息:http://www.w3.org/graphics/svg/1.1/dtd/svg-framework.modhttp://www.w3.org/tr/2003/rec-svg11-20030114/rec-svg11-20030114.pdf

您可能会提供带有脚本元素的修改版本的SVG DTD或通过元素循环以防止脚本元素的存在。

它不会是完美的,但至少总比没有好。

您可以使用SVG Sanitize软件包:https://packagist.org/packages/enshrined/svg-sanitize

在编写答案的日期时,安装了500k。

use enshrinedsvgSanitizeSanitizer;
// 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

最新更新