日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

淺談 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 中返回時,例如:
// 某網站具有搜索功能,該功能通過 URL 參數接收用戶提供的搜索詞:
https://xxx.com/search?query=123
// 服務器在對此 URL 的響應中回顯提供的搜索詞:
<p>您搜索的是: 123</p>
// 如果服務器不對數據進行轉義等處理,則攻擊者可以構造如下鏈接進行攻擊:
https://xxx.com/search?query=<img src="empty.png" onerror ="alert('xss')">
// 該 URL 將導致以下響應,并運行 alert('xss'):
<p>您搜索的是: <img src="empty.png" onerror ="alert('xss')"></p>
// 如果有用戶請求攻擊者的 URL ,則攻擊者提供的腳本將在用戶的瀏覽器中執行。

存儲行 XSS

  • XSS 腳本來自服務器數據庫中
  • 攻擊者將惡意代碼提交到目標網站的數據庫中,普通用戶訪問網站時服務器將惡意代碼返回,瀏覽器默認執行,例子:
// 某個評論頁,能查看用戶評論。
// 攻擊者將惡意代碼當做評論提交,服務器沒對數據進行轉義等處理// 評論輸入:<textarea>
  <img src="empty.png" onerror ="alert('xss')">
</textarea>
// 則攻擊者提供的腳本將在所有訪問該評論頁的用戶瀏覽器執行

DOM 型 XSS

該漏洞存在于客戶端代碼,與服務器無關

  • 類似反射型,區別在于 DOM 型 XSS 并不會和后臺進行交互,前端直接將 URL 中的數據不做處理并動態插入到 HTML 中,是純粹的前端安全問題,要做防御也只能在客戶端上進行防御。

React 如何防止 XSS 攻擊

無論使用哪種攻擊方式,其本質就是將惡意代碼注入到應用中,瀏覽器去默認執行。React 官方中提到了 React DOM 在渲染所有輸入內容之前,默認會進行轉義。它可以確保在你的應用中,永遠不會注入那些并非自己明確編寫的內容。所有的內容在渲染之前都被轉換成了字符串,因此惡意代碼無法成功注入,從而有效地防止了 XSS 攻擊。我們具體看下:

自動轉義

React 在渲染 HTML 內容和渲染 DOM 屬性時都會將 "'&<> 這幾個字符進行轉義,轉義部分源碼如下:

for (index = match.index; index < str.length; index++) {
  switch (str.charCodeAt(index)) {
    case 34: // "
      escape = '"';
      break;
    case 38: // &
      escape = '&';
      break;
    case 39: // '
      escape = ''';
      break;
    case 60: // <
      escape = '<';
      break;
    case 62: // >
      escape = '>';
      break;
    default:
      continue;
    }
  }

這段代碼是 React 在渲染到瀏覽器前進行的轉義,可以看到對瀏覽器有特殊含義的字符都被轉義了,惡意代碼在渲染到 HTML 全都被轉成了字符串,如下:

// 一段惡意代碼
<img src="empty.png" onerror ="alert('xss')"> 
// 轉義后輸出到 html 中<img src="empty.png" onerror ="alert('xss')"> 

這樣就有效的防止了 XSS 攻擊。

JSX 語法

JSX 實際上是一種語法糖,Babel 會把 JSX 編譯成 React.createElement() 的函數調用,最終返回一個 ReactElement,以下為這幾個步驟對應的代碼:

// JSX
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);// 通過 babel 編譯后的代碼
const element = React.createElement(  'h1',
  {className: 'greeting'},
  'Hello, world!'
);// React.createElement() 方法返回的 ReactElement
const 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":"<img src="empty.png" onerror ="alert('xss')"/>"
      }  }}`;// 轉成 JSON
const parsedData = JSON.parse(storedData);
// 將數據渲染到頁面
render () {
  return <span> {parsedData} </span>; 
}

這段代碼中, 運行后會報以下錯誤,提示不是有效的 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":"<img onerror='alert("xss");' src='empty.png' />"}}"`;
// 經過 JSON 轉換const userProvideProps = JSON.parse(userProvidePropsString);// userProvideProps = {//   dangerouslySetInnerHTML: {//     "__html": `<img onerror='alert("xss");' src='empty.png' />`
//      }// };render() {     // 出于某種原因解析用戶提供的 JSON 并將對象作為 props 傳遞    return <div {...userProvideProps} /> 
}

這段代碼將用戶提供的數據進行 JSON 轉換后直接當做 div 的屬性,當用戶構造了類似例子中的特殊字符串時,頁面就會被注入惡意代碼,所以要注意平時在開發中不要直接使用用戶的輸入作為屬性。

使用用戶輸入的值來渲染 a 標簽的 href 屬性,或類似 img 標簽的 src 屬性等

const userWebsite = "JAVAscript:alert('xss');";
<a href={userWebsite}></a>

如果沒有對該 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

分享到:
標簽:攻擊 XSS
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定