您好,登錄后才能下訂單哦!
這篇文章主要介紹了React怎么防止XSS攻擊論$typeof的作用的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇React怎么防止XSS攻擊論$typeof的作用文章都會有所收獲,下面我們一起來看看吧。
先來簡單復習一下 JSX 的基礎知識。JSX 是React.createElement的語法糖
<div id="container">hello</div>
經過 babel
編譯后:
React.createElement( "div" /* type */, { id: "container" } /* props */, "hello" /* children */ );
React.createElement
最終返回的結果就是一個對象,如下:
{ type: 'div', props: { id: 'container', children: 'hello', }, key: null, ref: null, $$typeof: Symbol.for('react.element'), }
這就是一個 React element 對象。
我們甚至可以在代碼中直接寫 React element 對象,React 照樣能正常渲染我們的內容:
render() { return ( <div> {{ $$typeof: Symbol.for('react.element'), props: { dangerouslySetInnerHTML: { __html: '<img src="x" onerror="alert(1)">' }, }, ref: null, type: "div", }} </div> ); }
可以復制這段代碼本地運行一下,可以發現瀏覽器彈出一個彈窗,并且img
已經插入了 dom 中。
這里,$$typeof
的作用是啥?為什么使用 Symbol()
作為值?
在了解之前,我們先來簡單看下 XSS
攻擊
我們經常需要構造 HTML 字符串并插入到 DOM 中,比如:
const messageEl = document.getElementById("message"); var message = "hello world"; messageEl.innerHTML = "<p>" + message + "</p>";
頁面正常顯示。但是如果我們插入一些惡意代碼,比如:
const messageEl = document.getElementById("message"); var message = '<img src onerror="alert(1)">'; messageEl.innerHTML = "<p>" + message + "</p>";
此時頁面就會彈出一個彈窗,彈窗內容顯示為 1
因此,直接使用 innerHTML 插入文本內容,存在 XSS 攻擊的風險
為了解決類似的 XSS 攻擊方法,我們可以使用一些安全的 API 添加文本內容,比如:
使用 document.createTextNode('hello world')
插入文本節點。
或者使用 textContent
而不是 innerHTML
設置文本內容。
對于一些特殊字符,比如 <
、>
,我們可以進行轉義,將其轉換為 <
以及 >
對于富文本內容,我們可以設置黑名單,過濾一些屬性,比如 onerror
等。
React 使用 createTextNode
或者 textContent
設置文本內容。
對于下面的代碼:
render() { const { count } = this.state return ( <div onClick={() => this.setState({ count: count + 1})}> {count} </div> ); }
React 在渲染過程中會調用setTextContent
方法為div
節點設置內容,其中,第一次渲染時,直接設置div
節點的textContent
,第二次或者第二次以后的更新渲染,由于第一次設置了textContent
,因此div
的firstChild
值存在,是個文本節點。此時直接更新這個文本節點的nodeValue
即可
var setTextContent = function (node, text) { if (text) { var firstChild = node.firstChild; // 如果當前node節點已經設置過textContent,則firstChild不為空,是個文本節點TEXT_NODE if ( firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE ) { firstChild.nodeValue = text; return; } } // 第一次渲染,直接設置textContent node.textContent = text; };
綜上,對于普通的文本節點來說,由于 React 是采用 textContent 或者 createTextNode 的方式添加的,因此是不會存在 XSS 攻擊的,即使上面示例中,count 的值為 '<img src="x" onerror="alert(1)">'
也不會有被攻擊的風險
有時候我們確實需要顯示富文本的內容,React 提供了dangerouslySetInnerHTML
方便我們顯式的插入富文本內容
render() { return ( <div id="dangerous" dangerouslySetInnerHTML={{ __html: '<img src="x" onerror="alert(1)">' }} > </div> ); }
React 在為 DOM 更新屬性時,會判斷屬性的key
是不是dangerouslySetInnerHTML
,如果是的話,調用setInnerHTML
方法直接給 dom 的innerHTML
屬性設置文本內容
function setInitialDOMProperties( tag, domElement, rootContainerElement, nextProps ) { for (var propKey in nextProps) { if (propKey === "dangerouslySetInnerHTML") { var nextHtml = nextProp ? nextProp.__html : undefined; if (nextHtml != null) { setInnerHTML(domElement, nextHtml); } } } } var setInnerHTML = function (node, html) { node.innerHTML = html; };
可以看出,React 在處理富文本時,也僅僅是簡單的設置 DOM 的innerHTML
屬性來實現的。
對于富文本潛在的安全風險,交由開發者自行把控。
render() { const { text } = this.state return ( <div> {text} </div> ); }
假設這個text
是從后端返回來的,同時后端允許用戶存儲 JSON 對象,如果用戶傳入下面這樣的一個類似 React element 的對象:
{ type: "div", props: { dangerouslySetInnerHTML: { __html: '<img src="x" onerror="alert(1)">' }, }, ref: null }
別忘了前面說過,我們在 JSX 中直接插入 React element 對象也是能夠正常渲染的。
在這種情況下,在React0.13
版本時,這是一個潛在的XSS
攻擊,這個漏洞源于服務端。如果攻擊者惡意偽造一個類似 React element 對象的數據返回給前端,React 就會執行惡意代碼。但是 React 可以采取措施預防這種攻擊。
從React0.14
版本開始,React 為每個 element 都添加了一個Symbol
標志:
{ $$typeof: Symbol.for('react.element'), props: { id: 'container' }, ref: null, type: "div", }
這個行得通,是因為 JSON 不支持Symbol
。因此即使是服務端有風險漏洞并且返回一個 JSON,這個 JSON 也不會包含Symbol.for('react.element').
,在 Reconcile 階段,React 會檢查element.$$typeof
標志是否合法。不合法的話直接報錯,React 不能接受對象作為 children
專門使用 Symbol.for() 的好處是, Symbols 在 iframe 和 worker 等環境之間是全局的。因此,即使在更奇特的條件下,Symbols 也能在不同的應用程序之間傳遞受信任的元素。同樣,即使頁面上有多個 React 副本,它們仍然可以“同意”有效的 $$typeof 值
如果瀏覽器不支持Symbols
,React 使用0xeac7
代替
{ $$typeof: '0xeac7', }
關于“React怎么防止XSS攻擊論$typeof的作用”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“React怎么防止XSS攻擊論$typeof的作用”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。