《前端之路》 之 前端 安全 XSS 原理以及防禦手段
什麼是 XSS
一、XSS
什麼是 XSS
XSS,即 Cross Site Script , 翻譯過來就是 跨站指令碼攻擊;為了和 css 有所區分,因而在安全領域被稱為 XSS。
什麼是 XSS 攻擊
XSS 攻擊指的是 攻擊者在網站上注入惡意的客戶端程式碼,通過惡意指令碼對客戶端網頁進行篡改,從而在別的使用者瀏覽網頁的 時候,對使用者進行控制或者獲取 使用者對隱私資料的 這麼一種攻擊手段。
XSS 攻擊的方式 是什麼
XSS 攻擊可以分為3類:反射型(非持久型)、儲存型(持久型)、基於DOM。
XSS攻擊需要具備兩個條件:需要向web頁面注入惡意程式碼;這些惡意程式碼能夠被瀏覽器成功的執行。
使用者注入的 惡意指令碼一般包括 JavaScript 、HTML、Flash。很多種的 XSS 攻擊方式,但是共同點是: 將一些 隱私資料像:1、cookie、session 傳送給攻擊者。 2、將受害者重定向到一個由攻擊者控制的網站(俗稱釣魚網站),在受害者的機器上進行一些惡意操作。
反射型(非持久型)的 XSS 攻擊
XSS反射型攻擊,惡意程式碼並沒有儲存在目標網站,而是通過引誘使用者點選一個連結到目標網站的惡意連結來實施攻擊的。
直接這麼解釋還是有點難懂的。下面,我們還是來看個 demo
<a href="http://127.0.0.1:1212/login/<img src=''onerror='alert(document.cookie)'>" target="_blank" >這是 XSS 的惡意連結</a>
假設某使用者在黑客點釣魚網站上 點選了這個 帶有 XSS 攻擊的惡意連結。就會跳轉到 http://127.0.0.1:1212
這個網站上。剛好這個路徑下的 連結是會有一個 發生一個 get 請求。
那麼這個時候 <img src='' onerror='alert(document.cookie)'>
這部分的內容就被 當作 請求的 內容傳送給了 服務端。如果服務端 為對該 內容進行 XSS 防禦,直接返回給 瀏覽器。
那麼這個時候就會出現 XSS 攻擊了。 <img src='' onerror='alert(document.cookie)'>
這句程式碼被顯示在了 瀏覽器上,因為 img 標籤也具有 跨域屬性,直接執行了 onerror 中的 JS 程式碼。 黑客這個時候就可以 在目標網站上 為所欲為了。
比如這裡就是 簡單的 alert 了 所有的 cookie。但是,如果我是黑客的話,我肯定會把 使用者的 cookie、localStorage、等等重要資訊 全部上傳到我的伺服器,然後進行拿到各類想要的資訊。從而獲益。
儲存型(持久型)的 XSS 攻擊
儲存型(持久型)的 XSS 攻擊 和 反射型 其實也有異曲同工之妙呀。
這麼多,我哪裡記得住?
別慌,我們慢慢分析一波就都能記住啦~
惡意程式碼 通過表單提交的方式 被儲存到目標網站的伺服器中,這種攻擊具有較強的穩定性和永續性,比較常見場景是在部落格,論壇、OA、CRM等社交網站上,比如:某CRM系統的客戶投訴功能上存在XSS儲存型漏洞,黑客提交了惡意攻擊程式碼,當系統管理員檢視投訴資訊時惡意程式碼執行,竊取了客戶的資料,然而管理員毫不知情,這就是典型的XSS儲存型攻擊。
我們還是寫個 demo 來方便 理解吧
<div><textarea id="textarea" class="text"></textarea></div> <button id="btn" class="botton">submit</button>
大概就長這個樣子了:

textarea 內則為 帶有 xss 的程式碼,點選提交。直接 xhr 請求到 node 的服務端。
node 服務端 接收到 傳入的引數 不做任何 xss 防禦 直接儲存起來的 js demo
一般是儲存 sql 但是這裡方便起見 我們就直接存 memory-cache ,程式碼如下:
router.post("/upload", (ctx, next) => { let curData = JSON.stringify(ctx.request.body); cache.put("xss", curData); ctx.body = `<div>${curData}</div>`; });
我們請求 一個新的路徑來將 memory-cache 的值獲取到。 node 端 程式碼:
router.get("/getName", (ctx, next) => { let curData = cache.get("xss"); ctx.body = `<div>${JSON.parse(curData)}</div>`; });
接下來就是訪問 http://127.0.0.1:1212/getName
得到 如下 畫面:
當然,黑客不會 alert 你的 cookie 資訊。 直接 post 到 一個第三方的 伺服器上,然後直接模擬瀏覽器訪問,那就簡直了。
基於 DOM 的 XSS 攻擊
基於 DOM 的 XSS 攻擊是指通過惡意指令碼修改頁面的 DOM 結構,是純粹發生在客戶端的攻擊。
const divXss = document.getElementById("xss"); const xssbtn = document.getElementById("xssbtn"); const val = `'' onclick=alert(/xss/)`; xssbtn.addEventListener("click", function() { divXss.innerHTML = `<a href=${val}>testLink</a>`; });
當然上面的這個 val
往往是黑客 通過 input 或者 textarea 的 form表單提交引起的
當用戶下意識的去點選 這個新增的 dom 的時候,就會出現 如下 場景:
黑客又可以為所欲為了。
二、XSS 的 防禦
HttpOnly 防止劫取 Cookie
HttpOnly 最早由微軟提出,至今已經成為一個標準。瀏覽器將禁止頁面的Javascript 通過 document.cookie 獲取帶有 HttpOnly 屬性的Cookie。
上文有說到,攻擊者可以通過注入惡意指令碼獲取使用者的 Cookie 資訊。通常 Cookie 中都包含了使用者的登入憑證資訊,攻擊者在獲取到 Cookie 之後,則可以發起 Cookie 劫持攻擊。所以,嚴格來說,HttpOnly 並非阻止 XSS 攻擊,而是能阻止 XSS 攻擊後的 Cookie 劫持攻擊。
輸入檢查
不要相信使用者的任何輸入。 對於使用者的任何輸入要進行檢查、過濾和轉義。建立可信任的字元和 HTML 標籤白名單,對於不在白名單之列的字元或者標籤進行過濾或編碼。
在 XSS 防禦中,輸入檢查一般是檢查使用者輸入的資料中是否包含 <,> 等特殊字元,如果存在,則對特殊字元進行過濾或編碼,這種方式也稱為 XSS Filter。
而在一些前端框架中,都會有一份 decodingMap, 用於對使用者輸入所包含的特殊字元或標籤進行編碼或過濾,如 <,>,script,防止 XSS 攻擊:
// vuejs 中的 decodingMap
// 在 vuejs 中,如果輸入帶 script 標籤的內容,會直接過濾掉
const decodingMap = {
'<': '<',
'>': '>',
'"': '"',
'&': '&',
' ': '\n'
}
輸出檢查
使用者的輸入會存在問題,服務端的輸出也會存在問題。一般來說,除富文字的輸出外,在變數輸出到 HTML 頁面時,可以使用編碼或轉義的方式來防禦 XSS 攻擊。
例如利用 sanitize-html 對輸出內容進行有規則的過濾之後再輸出到頁面中。
本 demo 中的 koa 框架其實在輸出的時候處理了標籤:
這個時候 就會 減少 99% 的 xss 攻擊了。是不是發現選擇一款好的框架能節省好多的麻煩。
好了,這篇關於 XSS 的文章就介紹到 這裡了,彆著急 原始碼會放出來的。
全文的 demo 的原始碼地址: github原始碼地址
總結
一旦在DOM解析過程成出現不在預期內的改變,就有可能發生 XSS。
失控 就會出現 BUG。
防禦手段 既然 攻防的人都知道了,那麼自身程式碼的嚴謹程度就決定了整個專案的安度。
突然想起了 PDD ...
GitHub 地址:(歡迎 star 、歡迎推薦 : )