<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert('This app is probably vulnerable to XSS attacks!');
</script>
</svg>
看到<script>这个标签就全明白了,svg不仅是矢量图,里面可以内嵌脚本。
XSS攻击
这是如何发生的?只要你的Web应用允许用户上传、提交svg文件,内嵌在其中的恶意代码就可以妥妥的操作你应用页面里的DOM,余下的就是“常规”XSS攻击的事情。
HTML注入
SVG用XML语法和格式描述矢量,在XML中无法直接引用HTML。为了满足这方面的应用需求,SVG提供了一个叫foreignObject的元素,以便于开发者引入外部XML namespace下的元素。例如:
<body>标签下可以引入一个XHTML的namespace,在标签下的的内容,都会被浏览器解析执行。此时,phishing(钓鱼)、CSRF(伪造跨站请求)、same-origin bypass(绕过同源限制)的骚操作都可以逐一发生。
恶意递归XML Entity - “亿笑攻击”
所谓"Billion Laughs Attack",又称之为“XML炸弹”(XML Bomb)或者“实体指数扩张攻击”(Entity Exponential Expansion Attack),是通过创建一系列递归的XML定义,在内存中产生上十亿的特定字符串,从而导致DoS攻击。原理是构造恶意的XML实体文件以耗尽服务器可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中,上亿的特定字符串占用巨量内存,使得解析器解析非常慢,并使得可用资源耗尽,从而造成拒绝服务攻击。
制作这些"lol"(Lots of Laugh)的tricks在这里:
写一个制造“笑气弹”的svg:
加载它,你的机器将“狂笑”一阵 - 大概4到5秒。原因?现在的浏览器都能处理这类攻击,自动“制止”继续lol,但是通常需要4-5秒反应时间去判断和处理。
新型DoS攻击
所谓“道高一尺魔高一丈”,浏览器厂商有防,攻击者又有新的攻。这次是利用了svg中的这俩:xlink:href这个Attribute和<use>这个Element:
层层递归的套路,直到浏览器崩溃。
小结
SVG类型的内容资源,与其说是图片,还不如说是HTML的延伸扩展。所以,HTML所能被利用的攻击手段,也可能都适用于SVG。为了安全起见,原则上:
- svg资源不能以object甚至iframe的方式引入、加载
- 禁止用户上传svg
- 管控通过未授权信任的链接加载外部的svg资源
- 慎用<script>、<foreignObject>等比较强大但也有风险的标签
在FinClip小程序中能放心使用SVG吗
FinClip SDK是一个让任何App“瞬间”获得运行小程序能力的安全沙箱。运行其中的小程序,相比一般的网页应用,获得更强的安全防护。
沙箱环境
SDK启动的沙箱,提供一个纯 JavaScript 的解释执行环境,没有浏览器相关接口,无法操作 DOM、跳转。小程序业务逻辑相关的JavaScript代码均由沙箱创建的一个单独的线程去执行。界面渲染相关的任务,交由独立Webview 线程负责,通过逻辑层代码去控制界面渲染。沙箱不支持动态载入脚本,XSS攻击难以进行。
审核上架
FinClip的服务器端提供了对小程序上下架的管控能力。经过审核的小程序才能上架;出现问题时,则可以一键下架。每个FinClip小程序需要事先设置通讯域名,小程序只能跟指定的域名与进行网络通信,包括普通 HTTPS 请求、上传文件、下载文件和 WebSocket 通信,参考框架-网络。这些通讯域名,也都必须要求通过备案。这些种种的限制和管理模式,都进一步保障安全。
开发者在开发小程序时引用的SVG资源,在小程序上架的源头可以进行检测审核。
控制SVG引入加载的方式
如前文所述,在标准浏览器中,起码有四种方式加载SVG资源(加上<iframe>和<embed>的话,实际上有6种可能,但这两种都不推荐使用,可以排除)。
从安全使用的角度看,把svg当作普通的图片资源,通过<img>引入,技术上支持,只要文件是自己或者可信的第三方提供。以<object>方式加载,则是可以引入风险的,因为它能触发对svg中上述一些脚本的执行。
inline(内联)方式,在小程序中是较为安全的方式,svg内容变成了小程序页面代码的一部分,首先是开发者自行负责,而不是一个URL指向网上什么第三方的黑盒子资源,其次小程序审核上架的时候也可以检测其有无涉及上述有安全风险的标签使用方式。
FinClip目前对svg的支持,实际上合并了第三和第四种方式:即通过CSS中的background image加载svg图片,但是图片数据不是来自外部资源,而是inline生成的。
在FinClip小程序中SVG的打开方式
在小程序里成功使用SVG的诀窍在于这几处。
通过CSS background image加载,例如在你的 pages/index.fxml中:
其中,svg_content_data自然是由你的 pages/index.js 来负责产生了,它应该是长这个样子: