Java防止Xss注入json_浅谈 React 中的 XSS 攻击
作者:陳吉
轉發鏈接:https://mp.weixin.qq.com/s/HweEFh78WXLawyQr_Vsl5g
前言
前端一般會面臨 XSS 這樣的安全風險,但隨著 React 等現代前端框架的流行,使我們在平時開發時不用太關注安全問題。以 React 為例,React 從設計層面上就具備了很好的防御 XSS 的能力。本文將以源碼角度,看看 React 做了哪些事情來實現這種安全性的。
XSS 攻擊是什么
Cross-Site Scripting(跨站腳本攻擊)簡稱 XSS,是一種代碼注入攻擊。XSS 攻擊通常指的是利用網頁的漏洞,攻擊者通過巧妙的方法注入 XSS 代碼到網頁,因為瀏覽器無法分辨哪些腳本是可信的,導致 XSS 腳本被執行。XSS 腳本通常能夠竊取用戶數據并發送到攻擊者的網站,或者冒充用戶,調用目標網站接口并執行攻擊者指定的操作。
XSS 攻擊類型
反射行 XSS
- XSS 腳本來自當前 HTTP 請求
- 當服務器在 HTTP 請求中接收數據并將該數據拼接在 HTML 中返回時,例如:
您搜索的是:?123
//?如果服務器不對數據進行轉義等處理,則攻擊者可以構造如下鏈接進行攻擊:https://xxx.com/search?query=//?該 URL 將導致以下響應,并運行 alert('xss'):您搜索的是:?
//?如果有用戶請求攻擊者的 URL ,則攻擊者提供的腳本將在用戶的瀏覽器中執行。存儲行 XSS
- XSS 腳本來自服務器數據庫中
- 攻擊者將惡意代碼提交到目標網站的數據庫中,普通用戶訪問網站時服務器將惡意代碼返回,瀏覽器默認執行,例子:
DOM 型 XSS
該漏洞存在于客戶端代碼,與服務器無關
- 類似反射型,區別在于 DOM 型 XSS 并不會和后臺進行交互,前端直接將 URL 中的數據不做處理并動態插入到 HTML 中,是純粹的前端安全問題,要做防御也只能在客戶端上進行防御。
React 如何防止 XSS 攻擊
無論使用哪種攻擊方式,其本質就是將惡意代碼注入到應用中,瀏覽器去默認執行。React 官方中提到了 React DOM 在渲染所有輸入內容之前,默認會進行轉義。它可以確保在你的應用中,永遠不會注入那些并非自己明確編寫的內容。所有的內容在渲染之前都被轉換成了字符串,因此惡意代碼無法成功注入,從而有效地防止了 XSS 攻擊。我們具體看下:
自動轉義
React 在渲染 HTML 內容和渲染 DOM 屬性時都會將 "'&<> 這幾個字符進行轉義,轉義部分源碼如下:
for?(index?=?match.index;?index???????escape?=?'>';??????break;????default:??????continue;????}??}這段代碼是 React 在渲染到瀏覽器前進行的轉義,可以看到對瀏覽器有特殊含義的字符都被轉義了,惡意代碼在渲染到 HTML 全都被轉成了字符串,如下:
//?一段惡意代碼?//?轉義后輸出到?html?中?這樣就有效的防止了 XSS 攻擊。
JSX 語法
JSX 實際上是一種語法糖,Babel 會把 JSX 編譯成 React.createElement() 的函數調用,最終返回一個 ReactElement,以下為這幾個步驟對應的代碼:
//?JSXconst?element?=?(??????Hello,?world!??
);//?通過?babel?編譯后的代碼const?element?=?React.createElement(??'h1',??{className:?'greeting'},??'Hello,?world!');//?React.createElement()?方法返回的?ReactElementconst?element?=?{??$$typeof:?Symbol('react.element'),??type:?'h1',??key:?null,??props:?{????children:?'Hello,?world!',??????className:?'greeting'?????}??...}我們可以看到,最終渲染的內容是在 Children 屬性中,那了解了 JSX 的原理后,我們來試試能否通過構造特殊的 Children 進行 XSS 注入,來看下面一段代碼:
const?storedData?=?`{??"ref":null,??"type":"body",??"props":{??"dangerouslySetInnerHTML":{??"__html":""??????}??}}`;//?轉成?JSONconst?parsedData?=?JSON.parse(storedData);//?將數據渲染到頁面render?()?{??return??{parsedData}?;?}這段代碼中, 運行后會報以下錯誤,提示不是有效的 ReactChild
Uncaught?(in?promise)?Error:?Objects?are?not?valid?as?a?React?child?(found:?object?with?keys?{ref,?type,?props}).?If?you?meant?to?render?a?collection?of?children,?use?an?array?instead.那究竟是哪里出問題了?我們看一下 ReactElement 的源碼:
const?symbolFor?=?Symbol.for;REACT_ELEMENT_TYPE?=?symbolFor('react.element');const?ReactElement?=?function(type,?key,?ref,?self,?source,?owner,?props)?{??const?element?=?{????//?這個?tag?唯一標識了此為?ReactElement????$$typeof:?REACT_ELEMENT_TYPE,????//?元素的內置屬性????type:?type,????key:?key,????ref:?ref,????props:?props,????//?記錄創建此元素的組件????_owner:?owner,??};??...??return?element;}注意到其中有個屬性是 $$typeof,它是用來標記此對象是一個 ReactElement,React 在進行渲染前會通過此屬性進行校驗,校驗不通過將會拋出上面的錯誤。React 利用這個屬性來防止通過構造特殊的 Children 來進行的 XSS 攻擊,原因是 $$typeof 是個 Symbol 類型,進行 JSON 轉換后會 Symbol 值會丟失,無法在前后端進行傳輸。如果用戶提交了特殊的 Children,也無法進行渲染,利用此特性,可以防止存儲型的 XSS 攻擊。
在 React 中可引起漏洞的一些寫法
使用 dangerouslySetInnerHTML
dangerouslySetInnerHTML 是 React 為瀏覽器 DOM 提供 innerHTML 的替換方案。通常來講,使用代碼直接設置 HTML 存在風險,因為很容易使用戶暴露在 XSS 攻擊下,因為當使用 dangerouslySetInnerHTML 時,React 將不會對輸入進行任何處理并直接渲染到 HTML 中,如果攻擊者在 dangerouslySetInnerHTML 傳入了惡意代碼,那么瀏覽器將會運行惡意代碼。看下源碼:
function?getNonChildrenInnerMarkup(props)?{??const?innerHTML?=?props.dangerouslySetInnerHTML;?//?有dangerouslySetInnerHTML屬性,會不經轉義就渲染__html的內容??if?(innerHTML?!=?null)?{????if?(innerHTML.__html?!=?null)?{??????return?innerHTML.__html;????}??}?else?{????const?content?=?props.children;????if?(typeof?content?===?'string'?||?typeof?content?===?'number')?{??????return?escapeTextForBrowser(content);????}??}??return?null;}所以平時開發時最好避免使用 dangerouslySetInnerHTML,如果不得不使用的話,前端或服務端必須對輸入進行相關驗證,例如對特殊輸入進行過濾、轉義等處理。前端這邊處理的話,推薦使用白名單過濾 (https://jsxss.com/zh/index.html),通過白名單控制允許的 HTML 標簽及各標簽的屬性。
通過用戶提供的對象來創建 React 組件
舉個例子:
//?用戶的輸入const?userProvidePropsString?=?`{"dangerouslySetInnerHTML":{"__html":""}}"`;//?經過?JSON?轉換const?userProvideProps?=?JSON.parse(userProvidePropsString);//?userProvideProps?=?{//???dangerouslySetInnerHTML:?{//?????"__html":?``//??????}//?};render()?{?????//?出于某種原因解析用戶提供的?JSON?并將對象作為?props?傳遞????return?這段代碼將用戶提供的數據進行 JSON 轉換后直接當做 div 的屬性,當用戶構造了類似例子中的特殊字符串時,頁面就會被注入惡意代碼,所以要注意平時在開發中不要直接使用用戶的輸入作為屬性。
使用用戶輸入的值來渲染 a 標簽的 href 屬性,或類似 img 標簽的 src 屬性等
const?userWebsite?=?"javascript:alert('xss');";如果沒有對該 URL 進行過濾以防止通過 javascript: 或 data: 來執行 JavaScript,則攻擊者可以構造 XSS 攻擊,此處會有潛在的安全問題。用戶提供的 URL 需要在前端或者服務端在入庫之前進行驗證并過濾。
服務端如何防止 XSS 攻擊
服務端作為最后一道防線,也需要做一些措施以防止 XSS 攻擊,一般涉及以下幾方面:
- 在接收到用戶輸入時,需要對輸入進行盡可能嚴格的過濾,過濾或移除特殊的 HTML 標簽、JS 事件的關鍵字等。
- 在輸出時對數據進行轉義,根據輸出語境 (html/javascript/css/url),進行對應的轉義
- 對關鍵 Cookie 設置 http-only 屬性,JS腳本就不能訪問到 http-only 的 Cookie 了
- 利用 CSP (https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP) 來抵御或者削弱 XSS 攻擊,一個 CSP 兼容的瀏覽器將會僅執行從白名單域獲取到的腳本文件,忽略所有的其他腳本 (包括內聯腳本和 HTML 的事件處理屬性)
總結
出現 XSS 漏洞本質上是輸入輸出驗證不充分,React 在設計上已經很安全了,但是一些反模式的寫法還是會引起安全漏洞。Vue 也是類似,Vue 做的安全措施主要也是轉義,HTML 的內容和動態綁定的屬性都會進行轉義。無論使用 React 或 Vue 等前端框架,都不能百分百的防止 XSS 攻擊,所以服務端必須對前端參數做一些驗證,包括但不限于特殊字符轉義、標簽、屬性白名單過濾等。一旦出現安全問題一般都是挺嚴重的,不管是敏感數據被竊取或者用戶資金被盜,損失往往無法挽回。我們平時開發中需要保持安全意識,保持代碼的可靠性和安全性。
作者:陳吉
轉發鏈接:https://mp.weixin.qq.com/s/HweEFh78WXLawyQr_Vsl5g
總結
以上是生活随笔為你收集整理的Java防止Xss注入json_浅谈 React 中的 XSS 攻击的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海信智能电视价格明细报告
- 下一篇: 电脑硬盘数据恢复教程电脑硬盘文件如何恢复