Sanitizer:给你的DOM消消毒

开发 前端
业务中经常遇到需要处理「有风险的DOM」的场景,本文会介绍这两者的区别以及为DOM消毒的API —— Sanitizer。

[[428805]]

大家好,我卡颂。

业务中经常遇到需要处理「有风险的DOM」的场景,比如:

  • 各种工具的文本粘贴功能
  • 需要渲染服务端返回HTML的场景

为了阻止潜在的XSS攻击,有两个选择:

  • escape(转义)
  • sanitize(消毒)

本文会介绍这两者的区别以及为DOM消毒的API —— Sanitizer。

[[428806]]

本文内容来自Safe DOM manipulation with the Sanitizer API[1]

转义与消毒

假设,我们想将这样一段HTML字符串插入DOM:

  1. const str = "<img src='' onerror='alert(0)'>"

如果直接将其作为某个元素的innerHTML,img的onerror回调执行JS代码的能力会带来XSS风险。

一种常见解决方案是:转义字符串。

什么是escape

浏览器会将一些保留字符解析为HTML代码,比如:

  • <被解析为标签的开头
  • >被解析为标签的结尾
  • ''被解析为属性值的开头和结尾

为了将这些保留字符显示为文本(不被解析为HTML代码),可以将其替换为对应的entity(HTML实体):

  • <的实体为<
  • >的实体为>
  • ''的实体为"

这种将HTML字符替换为entity的方式被称为escape(转义)

什么是sanitize

对于上面的HTML字符串:

  1. const str = "<img src='' onerror='alert(0)'>"

除了转义''来规避XSS风险,还有一种更直观的思路:直接过滤掉onerror属性。

这种直接移除HTML字符串中有害的代码(比如<script>)的方式被称为sanitize(消毒)

需要用到一个API——Sanitizer[2]。

首先我们通过Sanitizer构造实例:

  1. const sanitizer = new Sanitizer(); 

调用实例的sanitizeFor方法,传入容器元素类型以及要消毒的HTML字符串:

  1. sanitizer.sanitizeFor("div", str); 

会得到一个HTMLDivElement(即我们传入的容器元素类型),其内部包含一个没有onerror属性的img:

默认情况下Sanitizer会移除所有可能导致JS执行的代码。

丰富的配置

Sanitizer不仅开箱即用,还提供丰富的白名单、黑名单配置:

  1. const config = { 
  2.   allowElements: [], 
  3.   blockElements: [], 
  4.   dropElements: [], 
  5.   allowAttributes: {}, 
  6.   dropAttributes: {}, 
  7.   allowCustomElements: true
  8.   allowComments: true 
  9. }; 
  10.  
  11. new Sanitizer(config) 

比如,allowElements定义元素白名单,只有名单内的元素会被保留,与之对应的blockElements是元素黑名单:

  1. const str = `hello <b><i>world</i></b>` 
  2.  
  3. new Sanitizer().sanitizeFor("div", str) 
  4. // <div>hello <b><i>world</i></b></div> 
  5.  
  6. new Sanitizer({allowElements: [ "b" ]}).sanitizeFor("div", str) 
  7. // <div>hello <b>world</b></div> 
  8.  
  9. new Sanitizer({blockElements: [ "b" ]}).sanitizeFor("div", str) 
  10. // <div>hello <i>world</i></div> 
  11.  
  12. new Sanitizer({allowElements: []}).sanitizeFor("div", str) 
  13. // <div>hello world</div> 

allowAttributes是属性白名单,与之对应的dropAttributes是属性黑名单,对于如下配置:

  1.   allowAttributes: {"style": ["span"]}, 
  2.   dropAttributes: {"id": ["*"]}} 

代表消毒后的HTML:

  • 只允许span元素拥有style属性
  • 移除所有元素(*通配符代表所有元素)的id属性

兼容性

这么香的API兼容性怎么样呢:

当前只有在Chrome 93之后,开启试验标识后可使用:

 

  1. about://flags/#enable-experimental-web-platform-features 

虽然原生Sanitizer离稳定还遥遥无期,但你可以使用DOMPurify[3]库实现类似功能。

后记

日常你更倾向使用escape还是sanitize呢?

参考资料

[1]Safe DOM manipulation with the Sanitizer API:

https://web.dev/sanitizer/

[2]Sanitizer:

https://wicg.github.io/sanitizer-api/

[3]DOMPurify:

https://github.com/cure53/DOMPurify

 

责任编辑:姜华 来源: 魔术师卡颂
相关推荐

2020-03-19 15:32:47

手机消毒病毒

2013-08-15 13:17:17

2017-08-16 01:01:12

anitizerAndroidBug

2015-07-30 11:36:48

Xcode7ClangAddress San

2020-03-25 20:31:23

物联网无人机技术

2010-09-09 17:19:07

HTML DOMXML DOM

2010-09-28 10:24:50

HTML DOMXML DOM

2010-09-28 11:11:23

XML DOMHTML DOM

2020-06-12 09:56:14

数据中心疫情技术

2021-01-18 07:15:22

虚拟DOM真实DOMJavaScript

2022-05-06 19:42:53

DOM

2021-01-11 07:51:16

DOM对象节点树

2022-07-01 07:31:18

AhooksDOM场景

2017-07-19 14:26:01

前端JavaScriptDOM

2017-01-15 10:22:49

安全可视化迪普科技信息安全

2015-04-16 16:58:39

2020-12-17 10:53:03

擎朗智能机器人

2015-08-10 10:58:53

dompropertyattribute

2010-09-28 15:27:09

JavaScript
点赞
收藏

51CTO技术栈公众号