找回密码
 立即注册

QQ登录

只需一步,快速开始

葡萄城花卷
超级版主   /  发表于:2021-12-9 16:12  /   查看:2664  /  回复:0
1018号, W3C中网络平台孵化器小组(Web Platform Incubator Community Group)公布了HTML Sanitizer API的规范草案。这份草案用来解决浏览器如何解决XSS攻击问题。
image.png327592772.png
网络安全中比较让开发者们头疼的一类是XSS跨站点脚本攻击。这种攻击通常指的是利用网页开发时留下的漏洞,将恶意指令代码注入到网页,使用户加载并执行攻击者恶意制造的网页程序。
这些恶意代码没有经过过滤,与网站的正常代码混在一起,浏览器无法分辨哪些内容是可信的,恶意脚本就会被执行。而XSS攻击的核心有两个步骤:1、攻击者提交恶意代码;2、浏览器执行恶意代码。
为了解决这两步恶意攻击,通常有以下手段,
1、增加过滤条件
2、只进行纯前端行渲染,将数据和代码内容分开
3、对HTML充分转义
以上手段步骤繁琐,需要注意的内容也很多。为了让开发者更加便捷地解决XSS攻击的问题,浏览器现提供了原生的XSS攻击消毒能力。
HTML Sanitizer API——这份由谷歌、MozillaCure53联手发起提供的API即将最终完成,通过这个浏览器原生API我们可以更加轻松地保护Web应用程序免受XSS的攻击。
接下来我们一起来了解一下这个安全API吧。
Sanitizer API简介
Sanitizer API可以让浏览器直接从网站动态更新的标记中删除恶意代码。当有恶意HTML字符串、文档或文档片段对象想插入现有DOM之中,我们可以使用HTML Sanitizer API直接将这些内容清理。有点像电脑的安全卫士应用,可以清除风险内容。
使用Sanitizer API有以下三个优点:
-       减少Web应用程序中跨站点脚本的攻击次数
-       保证HTML输出内容在当前用户代理中安全使用

-       Sanitizer API 的可用性很强
image.png402005919.png
Sanitizer API的特性
Sanitizer APIHTML字符串安全打开新世界大门,将所有的功能大致分类,可以分为以下三个主要特性:
1.对用户输入进行杀毒
Sanitizer API的主要功能是接受字符串并将其转换为更安全的字符串。这些转换后的字符串不会执行额外的JavaScript,并确保应用程序受到XSS攻击的保护。
2.浏览器内置
该库在浏览器安装的时候一同预装,并在发现bug或出现新的攻击时进行更新。相当于我们的浏览器有了内置的杀毒措施,无需导入任何外部库。
3.使用简洁安全
在使用了Sanitizer API之后,浏览器就有了一个强大又安全的解析器,作为一个成熟的浏览器,它知道如何处理DOM中每个元素的活动。相比之下,用JavaScript开发的外部解析器不仅成本高昂,同时很容易跟不上前端大环境的更新速度。

说完了这些特性,让我们一起来看看这个API的具体用法。
image.png989063110.png
Sanitizer API的使用
Sanitizer API使用Sanitizer()方法构造函数,Sanitizer类进行配置。
官方提供了三种基础清理方式:
1、清理隐藏上下文的字符串

Element.setHTML() 用于解析和清理字符串,并立即将其插入DOM,这个方法适用于目标DOM元素已知且HTML内容为字符串的情况。
  1. const $div = document.querySelector('div')
  2. const user_input = `<em>Hello There</em><img src="" onerror=alert(0)>` // The user string.
  3. const sanitizer = new Sanitizer() // Our Sanitizer
  4. // We want to insert the HTML in user_string into a target element with id
  5. // target. That is, we want the equivalent of target.innerHTML = value, except
  6. // without the XSS risks.
  7. $div.setHTML(user_input, sanitizer) // <div><em>Hello There</em><img src=""></div>

复制代码
2、清理给定上下文的字符串
Sanitizer.sanitizeFor() 用于解析、清理稍后准备添加到DOM中的字符串。

适用于HTML内容是字符串且目标DOM元素类型已知(例如divspan)的情况。
  1. const user_input = `<em>Hello There</em><img src="" onerror=alert(0)>`
  2. const sanitizer = new Sanitizer()
  3. // Later:
  4. // The first parameter describes the node type this result is intended for.
  5. sanitizer.sanitizeFor("div", user_input) // HTMLDivElement <div>

复制代码
需要注意的是, HTMLElement.innerHTML 的清理输出结果是字符串格式。
  1. sanitizer.sanitizeFor("div", user_input).innerHTML // <em>Hello There</em><img src="">
复制代码
3、清理节点

对于已经有用户控制的DocumentFragmentSanitizer.sanitize()可以直接对DOM树节点进行清理。
  1. // Case: The input data is available as a tree of DOM nodes.
  2. const sanitizer = new Sanitizer()
  3. const $userDiv = ...;
  4. $div.replaceChildren(s.sanitize($userDiv));
复制代码
除了以上提到的三种方式之外,SanitizerAPI通过删除、过滤属性和标记来修改HTML字符串。

举个“栗子”。
image.png403939513.png
-       删除某些标记(script,marquee, head, frame, menu, object, etc.)并保留content标签。
-       移除大多属性,只保留<a>标签和colspanson<td>,<th>标签上的HREF。
-       筛选出可能导致风险脚本执行的内容。
默认设置中,这个安全API只用来防止XSS的出现。但是一些情况下我们也需要自定义设置,下面介绍一些常用的配置。
自定义消毒

创建一个配置对象,并在初始化Sanitizer API时将其传递给构造函数。

  1. const config = {
  2.   allowElements: [],
  3.   blockElements: [],
  4.   dropElements: [],
  5.   allowAttributes: {},
  6.   dropAttributes: {},
  7.   allowCustomElements: true,
  8.   allowComments: true
  9. };
  10. // sanitized result is customized by configuration
  11. new Sanitizer(config)
复制代码

下面是一些常用方法:
-       allowElements 对指定输入进行保留
-       blockElements 删除内容中需要保留的部分
-       dropElements 删除指定内容,包括输入的内容

  1. -        const str = `hello <b><i>there</i></b>`
  2. -       
  3. -        new Sanitizer().sanitizeFor("div", str)
  4. -        // <div>hello <b><i>there</i></b></div>
  5. -       
  6. -        new Sanitizer({allowElements: [ "b" ]}).sanitizeFor("div", str)
  7. -        // <div>hello <b>there</b></div>
  8. -       
  9. -        new Sanitizer({blockElements: [ "b" ]}).sanitizeFor("div", str)
  10. -        // <div>hello <i>there</i></div>
  11. -       
  12. -        new Sanitizer({allowElements: []}).sanitizeFor("div", str)
  13. -        // <div>hello there</div>
复制代码
-       allowAttributes和dropAttributes这两个参数可以自定义需要保留或者删除的部分。
  1. const str = `<span id=foo class=bar style="color: red">hello there</span>`

  2. new Sanitizer().sanitizeFor("div", str)
  3. // <div><span id="foo" class="bar" style="color: red">hello there</span></div>

  4. new Sanitizer({allowAttributes: {"style": ["span"]}}).sanitizeFor("div", str)
  5. // <div><span style="color: red">hello there</span></div>

  6. new Sanitizer({dropAttributes: {"id": ["span"]}}).sanitizeFor("div", str)
  7. // <div><span class="bar" style="color: red">hello there</span></div>
复制代码
-       AllowCustomElements开启是否使用自定义元素
  1. -        const str = `<elem>hello there</elem>`
  2. -       
  3. -        new Sanitizer().sanitizeFor("div", str);
  4. -        // <div></div>
  5. -       
  6. -        new Sanitizer({ allowCustomElements: true,
  7. -                        allowElements: ["div", "elem"]
  8. -                      }).sanitizeFor("div", str);
  9. -        // <div><elem>hello there</elem></div>
复制代码
如果没有进行任何配置,会直接使用默认配置内容。

这个API看起来能为我们解决不少的问题,但是现在浏览器对其的支持还有限,更多功能还在持续完善中。我们也很期待看到功能更加完善的SanitizerAPI
image.png723496093.png

对它感兴趣的小伙伴在Chrome93+中可以通过about://flags/#enable-experimental-web-platform-features启用,Firefox中目前也在实验阶段,可以在about:configdom.security.sanitizer.enabled 设为true来启用。
关于数据安全的担忧
根据 Verizon 2020 年数据泄露调查报告(Verizon Business2020 年)显示,约90% 的数据泄露事件是由于跨站点脚本(XSS)和安全漏洞造成的。对于前端开发者而言,面对越发频繁的网络攻击,除了借助Sanitizer API等安全机制外,还可以考虑使用“数据与代码分离”的SpreadJS等前端表格控件。


0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部