10

我正在使用 d3.js 作为 SVG 动态创建图表。这些图表是根据经过身份验证的用户的选择动态生成的。生成这些图表后,用户可以选择将生成的 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 元素是一个隐藏的表单,用于 POST 数据:

<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。

那么:在将其写入文件之前,如何最好地清理或过滤提供给 conversion.php 的 SVG 数据?SVG 清理的当前状态是什么?PHP中有什么可用的?我应该使用基于白名单的方法来清理提供给 conversion.php 的 SVG 数据,还是有更好的方法?

(我不知道 XSLT,虽然我可以尝试学习它;我希望尽可能多地在 PHP 中进行清理。使用 Windows Server 2008,因此任何使用外部工具的解决方案都需要在该生态系统中可用。)

4

3 回答 3

3

我正在使用 xml 和 PHP,但我完全不确定你的问题。请把它当作一个想法/建议,而不是更多。

SimpleXML 使用 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

在使用 simpleXML 加载文件之前。

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

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

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

这里有关于 1.1 DTD 的信息:http: //www.w3.org/Graphics/SVG/1.1/DTD/svg-framework.mod http://www.w3.org/TR/2003/REC-SVG11-20030114/ REC-SVG11-20030114.pdf

您可以为 SVG DTD 提供脚本元素的修改版本或循环遍历元素以防止脚本元素出现。

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

于 2013-03-04T17:34:03.340 回答
3

您需要使用 XML 解析器 + 白名单来清理 SVG。

因为 SVG 已经有多种执行代码的方法,并且未来的扩展可能会添加额外的方法,所以您根本无法将“已知危险”构造列入黑名单。只要您正确处理所有 XML 极端情况(例如 XSLT 样式表、实体扩展、外部实体引用),将安全元素和属性列入白名单就可以工作。

示例实现:https ://github.com/alnorris/SVG-Sanitizer/blob/master/SvgSanitizer.php (MIT 许可)或https://github.com/darylldoyle/svg-sanitizer(GPL v2 许可)

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

于 2018-08-28T07:54:22.007 回答
2

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

在撰写此答案之日已安装 500k。

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
于 2019-05-23T12:04:20.710 回答