8

JavaScript Sanitizer API:原生WEB安全API出现啦

 2 years ago
source link: https://my.oschina.net/powertoolsteam/blog/5336257
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

JavaScript Sanitizer API:原生WEB安全API出现啦

10月18号, W3C中网络平台孵化器小组(Web Platform Incubator Community Group)公布了HTML Sanitizer API的规范草案。这份草案用来解决浏览器如何解决XSS攻击问题。

网络安全中比较让开发者们头疼的一类是XSS跨站点脚本攻击。这种攻击通常指的是通过利用网页开发时留下的漏洞,即将恶意指令代码注入到网页,使用户加载并执行攻击者恶意制造的网页程序。

这些恶意代码没有经过过滤,与网站的正常代码混在一起,浏览器无法分辨哪些内容是可信的,恶意脚本就会被执行。而XSS攻击的核心有两个步骤:1、处理攻击者提交恶意代码;2、浏览器执行恶意代码。

为了解决在这两步恶意攻击中解决这个问题,通常有以下手段,

  1. 增加过滤条件
  2. 只进行纯前端行渲染,将数据和代码内容分开
  3. 对HTML充分转义

以上手段这些步骤繁琐,需要注意的内容也很多。为了让开发者更加便捷地解决XSS攻击的问题,浏览器现提供了原生的XSS攻击消毒能力。

HTML Sanitizer API——这份由谷歌、Mozilla和Cure53联手发起提供的API即将最终完成,通过这个浏览器原生API我们可以更加轻松地保护Web应用程序免受XSS的攻击。

接下来我们一起来了解一下这个安全API吧。

Sanitizer API简介

Sanitizer API可以让浏览器直接从网站动态更新的标记中删除恶意代码。当有恶意HTML字符串、和文档或文档片段对象想插入现有DOM之中,我们可以使用HTML Sanitizer API直接将这些内容清理。有点像电脑的安全卫士应用,可以清除风险内容。

使用Sanitizer API有以下三个优点:

  • 减少Web应用程序中跨站点脚本的攻击次数
  • 保证HTML输出内容在当前用户代理中安全使用
  • Sanitizer API 的可用性很强

Sanitizer API的特性

Sanitizer API为HTML字符串安全打开新世界大门,将所有的功能大致分类,可以分为以下三个主要特性:

1.对用户输入进行杀毒

Sanitizer API的主要功能是接受字符串并将其转换为更安全的字符串。这些转换后的字符串不会执行额外的JavaScript,并确保应用程序受到XSS攻击的保护。

2.浏览器内置

该库在浏览器安装的时候一同预装,并在发现bug或出现新的攻击时进行更新。相当于我们的浏览器有了内置的杀毒措施,无需导入任何外部库。

3.使用简洁安全

在使用了Sanitizer API之后,浏览器此时就有了一个强大又安全的解析器,作为一个成熟的浏览器,它知道如何处理DOM中每个元素的活动。相比之下,用JavaScript开发的外部解析器不仅成本高昂,同时很容易跟不上前端大环境的更新速度。

说完了这些使用上的亮点特性,让我们一起来看看这个API的具体用法。

Sanitizer API的使用

Sanitizer API使用Sanitizer()方法构造函数,Sanitizer类进行配置。

官方提供了三种基础清理方式:

1、清理隐藏上下文的字符串

Element.setHTML() 用于解析和清理字符串,并立即将其插入DOM,这个方法适用于目标DOM元素已知且HTML内容为字符串的情况。

const $div = document.querySelector('div')
const user_input = `<em>Hello There</em><img src="" onerror="alert(0)">` // The user string.
const sanitizer = new Sanitizer() // Our Sanitizer
// We want to insert the HTML in user_string into a target element with id
// target. That is, we want the equivalent of target.innerHTML = value, except
// without the XSS risks.
$div.setHTML(user_input, sanitizer) // <div><em>Hello There</em><img src=""></div>



2、清理给定上下的文字符串

Sanitizer.sanitizeFor() 用于解析、清理和准备稍后准备添加到DOM中的字符串。

适用于HTML内容是字符串,并且目标DOM元素类型已知(例如div、span)的情况。

const user_input = `<em>Hello There</em><img src="" onerror="alert(0)">`
const sanitizer = new Sanitizer()
// Later:
// The first parameter describes the node type this result is intended for.
sanitizer.sanitizeFor("div", user_input) // HTMLDivElement <div>


需要注意的是, HTMLElement中 .innerHTML 的清理输出结果是字符串格式。

sanitizer.sanitizeFor("div", user_input).innerHTML // <em>Hello There</em><img src="">

3、清理请理节点

对于已经有用户控制的DocumentFragment,Sanitizer.sanitize()可以直接对DOM树节点进行清理。

// Case: The input data is available as a tree of DOM nodes.
const sanitizer = new Sanitizer()
const $userDiv = ...;
$div.replaceChildren(s.sanitize($userDiv));

除了以上提到的三种方式之外,SanitizerAPI通过删除和、过滤属性和标记来修改HTML字符串。

举个“栗子”。

  • 删除某些标记(script, marquee, head, frame, menu, object, etc.)并保留content标签。
  • 移除大多属性,只保留<a>标签和colspanson,标签上的HREF。
  • 筛选出可能导致风险脚本执行的内容。

默认设置中,这个安全API只用来防止XSS的出现。但是一些情况下我们也需要自定义自义设置,下面介绍一些常用的配置。

自定义消毒

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

const config = {
  allowElements: [],
  blockElements: [],
  dropElements: [],
  allowAttributes: {},
  dropAttributes: {},
  allowCustomElements: true,
  allowComments: true
};
// sanitized result is customized by configuration
new Sanitizer(config)


下面是一些常用方法:

  • allowElements 对指定输入进行保留
  • blockElements blockElements 删除内容中需要保留的部分
  • dropElements dropElements 删除指定内容,包括输入的内容
const str = `hello <b><i>there</i></b>`

new Sanitizer().sanitizeFor("div", str)
// <div>hello <b><i>there</i></b></div>

new Sanitizer({allowElements: [ "b" ]}).sanitizeFor("div", str)
// <div>hello <b>there</b></div>

new Sanitizer({blockElements: [ "b" ]}).sanitizeFor("div", str)
// <div>hello <i>there</i></div>

new Sanitizer({allowElements: []}).sanitizeFor("div", str)
// <div>hello there</div>

  • allowAttributes和dropAttributes这两个参数可以自定义需要保留或者需要删除的部分。
const str = `<span id="foo" class="bar" style="color: red">hello there</span>`

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

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

new Sanitizer({dropAttributes: {"id": ["span"]}}).sanitizeFor("div", str)
// <div><span class="bar" style="color: red">hello there</span></div>

  • AllowCustomElements开启是否使用自定义元素
const str = `<elem>hello there</elem>`

new Sanitizer().sanitizeFor("div", str);
// <div></div>

new Sanitizer({ allowCustomElements: true,
                allowElements: ["div", "elem"]
              }).sanitizeFor("div", str);
// <div><elem>hello there</elem></div>


如果没有进行任何配置,会直接使用默认配置内容。

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

对它感兴趣的小伙伴在Chrome93+中可以通过about://flags/#enable-experimental-web-platform-features启用,Firefox中目前也在实验阶段,可以在about:config将dom.security.sanitizer.enabled 设为true来启用。

了解更多内容可以查看:https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API

关于数据安全的担忧

根据 Verizon 2020 年数据泄露调查报告(Verizon Business,2020 年)显示,约90% 的数据泄露事件是由于跨站点脚本((XSS))和安全漏洞造成的。对于前端开发者而言,面对越发频繁的网络攻击,除了借助Sanitizer API等安全机制外,还可以考虑使用"数据与代码分离"的SpreadJS等前端表格控件。</a></div>


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK