10月18號(hào), W3C中網(wǎng)絡(luò)平臺(tái)孵化器小組(Web Platform Incubator Community Group)公布了html Sanitizer API的規(guī)范草案。這份草案用來解決瀏覽器如何解決XSS攻擊問題。
網(wǎng)絡(luò)安全中比較讓開發(fā)者們頭疼的一類是XSS跨站點(diǎn)腳本攻擊。這種攻擊通常指的是通過利用網(wǎng)頁開發(fā)時(shí)留下的漏洞,即將惡意指令代碼注入到網(wǎng)頁,使用戶加載并執(zhí)行攻擊者惡意制造的網(wǎng)頁程序。
這些惡意代碼沒有經(jīng)過過濾,與網(wǎng)站的正常代碼混在一起,瀏覽器無法分辨哪些內(nèi)容是可信的,惡意腳本就會(huì)被執(zhí)行。而XSS攻擊的核心有兩個(gè)步驟:1、處理攻擊者提交惡意代碼;2、瀏覽器執(zhí)行惡意代碼。
為了解決在這兩步惡意攻擊中解決這個(gè)問題,通常有以下手段,
- 增加過濾條件
- 只進(jìn)行純前端行渲染,將數(shù)據(jù)和代碼內(nèi)容分開
- 對(duì)HTML充分轉(zhuǎn)義
以上手段這些步驟繁瑣,需要注意的內(nèi)容也很多。為了讓開發(fā)者更加便捷地解決XSS攻擊的問題,瀏覽器現(xiàn)提供了原生的XSS攻擊消毒能力。
HTML Sanitizer API——這份由谷歌、Mozilla和Cure53聯(lián)手發(fā)起提供的API即將最終完成,通過這個(gè)瀏覽器原生API我們可以更加輕松地保護(hù)Web應(yīng)用程序免受XSS的攻擊。
接下來我們一起來了解一下這個(gè)安全API吧。
Sanitizer API簡(jiǎn)介
Sanitizer API可以讓瀏覽器直接從網(wǎng)站動(dòng)態(tài)更新的標(biāo)記中刪除惡意代碼。當(dāng)有惡意HTML字符串、和文檔或文檔片段對(duì)象想插入現(xiàn)有DOM之中,我們可以使用HTML Sanitizer API直接將這些內(nèi)容清理。有點(diǎn)像電腦的安全衛(wèi)士應(yīng)用,可以清除風(fēng)險(xiǎn)內(nèi)容。
使用Sanitizer API有以下三個(gè)優(yōu)點(diǎn):
- 減少Web應(yīng)用程序中跨站點(diǎn)腳本的攻擊次數(shù)
- 保證HTML輸出內(nèi)容在當(dāng)前用戶代理中安全使用
- Sanitizer API 的可用性很強(qiáng)
Sanitizer API的特性
Sanitizer API為HTML字符串安全打開新世界大門,將所有的功能大致分類,可以分為以下三個(gè)主要特性:
1.對(duì)用戶輸入進(jìn)行殺毒
Sanitizer API的主要功能是接受字符串并將其轉(zhuǎn)換為更安全的字符串。這些轉(zhuǎn)換后的字符串不會(huì)執(zhí)行額外的JAVAScript,并確保應(yīng)用程序受到XSS攻擊的保護(hù)。
2.瀏覽器內(nèi)置
該庫在瀏覽器安裝的時(shí)候一同預(yù)裝,并在發(fā)現(xiàn)bug或出現(xiàn)新的攻擊時(shí)進(jìn)行更新。相當(dāng)于我們的瀏覽器有了內(nèi)置的殺毒措施,無需導(dǎo)入任何外部庫。
3.使用簡(jiǎn)潔安全
在使用了Sanitizer API之后,瀏覽器此時(shí)就有了一個(gè)強(qiáng)大又安全的解析器,作為一個(gè)成熟的瀏覽器,它知道如何處理DOM中每個(gè)元素的活動(dòng)。相比之下,用JavaScript開發(fā)的外部解析器不僅成本高昂,同時(shí)很容易跟不上前端大環(huán)境的更新速度。
說完了這些使用上的亮點(diǎn)特性,讓我們一起來看看這個(gè)API的具體用法。
Sanitizer API的使用
Sanitizer API使用Sanitizer()方法構(gòu)造函數(shù),Sanitizer類進(jìn)行配置。
官方提供了三種基礎(chǔ)清理方式:
1、清理隱藏上下文的字符串
Element.setHTML() 用于解析和清理字符串,并立即將其插入DOM,這個(gè)方法適用于目標(biāo)DOM元素已知且HTML內(nèi)容為字符串的情況。
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() 用于解析、清理和準(zhǔn)備稍后準(zhǔn)備添加到DOM中的字符串。
適用于HTML內(nèi)容是字符串,并且目標(biāo)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 的清理輸出結(jié)果是字符串格式。
sanitizer.sanitizeFor("div", user_input).innerHTML // <em>Hello There</em><img src="">
3、清理請(qǐng)理節(jié)點(diǎn)
對(duì)于已經(jīng)有用戶控制的DocumentFragment,Sanitizer.sanitize()可以直接對(duì)DOM樹節(jié)點(diǎn)進(jìn)行清理。
// Case: The input data is available as a tree of DOM nodes.
const sanitizer = new Sanitizer()
const $userDiv = ...;
$div.replaceChildren(s.sanitize($userDiv));
除了以上提到的三種方式之外,SanitizerAPI通過刪除和、過濾屬性和標(biāo)記來修改HTML字符串。
舉個(gè)“栗子”。
- 刪除某些標(biāo)記(script, marquee, head, frame, menu, object, etc.)并保留content標(biāo)簽。
- 移除大多屬性,只保留<a>標(biāo)簽和colspanson<td>,<th>標(biāo)簽上的HREF。
- 篩選出可能導(dǎo)致風(fēng)險(xiǎn)腳本執(zhí)行的內(nèi)容。
默認(rèn)設(shè)置中,這個(gè)安全API只用來防止XSS的出現(xiàn)。但是一些情況下我們也需要自定義自義設(shè)置,下面介紹一些常用的配置。
自定義消毒
創(chuàng)建一個(gè)配置對(duì)象,并在初始化Sanitizer API時(shí)將其傳遞給構(gòu)造函數(shù)。
const config = {
allowElements: [],
blockElements: [],
dropElements: [],
allowAttributes: {},
dropAttributes: {},
allowCustomElements: true,
allowComments: true
};
// sanitized result is customized by configuration
new Sanitizer(config)
下面是一些常用方法:
- allowElements 對(duì)指定輸入進(jìn)行保留
- blockElements blockElements 刪除內(nèi)容中需要保留的部分
- dropElements dropElements 刪除指定內(nèi)容,包括輸入的內(nèi)容
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這兩個(gè)參數(shù)可以自定義需要保留或者需要?jiǎng)h除的部分。
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>
如果沒有進(jìn)行任何配置,會(huì)直接使用默認(rèn)配置內(nèi)容。
這個(gè)API看起來能為我們解決不小少的問題,但是現(xiàn)在瀏覽器對(duì)其的支持還有限,更多功能還在持續(xù)完善中。我們也很期待看到功能更加完善的SanitizerAPI
對(duì)它感興趣的小伙伴在Chrome93+中可以通過about://flags/#
enable-experimental-web-platform-features啟用,F(xiàn)irefox中目前也在實(shí)驗(yàn)階段,可以在about:config將
dom.security.sanitizer.enabled設(shè)為true來啟用。
了解更多內(nèi)容可以查看:
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API
關(guān)于數(shù)據(jù)安全的擔(dān)憂
根據(jù) Verizon 2020 年數(shù)據(jù)泄露調(diào)查報(bào)告(Verizon Business,2020 年)顯示,約90% 的數(shù)據(jù)泄露事件是由于跨站點(diǎn)腳本((XSS))和安全漏洞造成的。對(duì)于前端開發(fā)者而言,面對(duì)越發(fā)頻繁的網(wǎng)絡(luò)攻擊,除了借助Sanitizer API等安全機(jī)制外,還可以考慮使用"數(shù)據(jù)與代碼分離"的SpreadJS等前端表格控件。
原文鏈接:
https://www.cnblogs.com/powertoolsteam/p/15627916.html