在 Web 安全方面,XSS 與 CSRF 能夠說是老生常談了。javascript
XSS,即 cross site script,跨站腳本攻擊,縮寫本來爲 CSS,但爲了和層疊樣式表(Cascading Style Sheet)區分,改成 XSS。php
XSS 攻擊是指攻擊者在網站上注入惡意腳本,使用戶在瀏覽使用網頁時進行惡意操做,注入腳本除了 JavaScript,還會有 CSS、HTML 等等。html
XSS 攻擊能夠分爲 3 種:反射型(非持久型)、存儲型(持久型)、DOM型。前端
反射型的 XSS 攻擊方式通常是攻擊者誘使用戶進行點擊惡意連接、提交表單等等操做,從而達到注入腳本的目的。java
舉個例子,假設某頁面會直接把搜索關鍵詞拼接到 HTML 頁面上顯示出來:數據庫
<p>您搜索的關鍵詞是:<?php showKeyword(keyword) ?></p>
當用戶點擊搜索後,會向服務端發送這樣的請求http://example/search?keyword=xxx
,而後服務端把 keyword 後面的字符進行 HTML 拼接而後返回。後端
這時,假如用戶點擊了一個惡意連接http://example/search?keyword=<script>xss攻擊腳本</script>
,那返回的 HTML 就會變成這樣:跨域
<p>您搜索的關鍵詞是:<script>xss攻擊腳本</script></p>
而後瀏覽器就會執行 script 裏面 xss 攻擊腳本,從而達到攻擊者的攻擊目的。瀏覽器
存儲型的 XSS 攻擊通常是攻擊者將惡意代碼做爲輸入的數據提交給服務端,而後服務端存儲到數據庫內,當有用戶請求這個數據後,服務端返回的數據實際上是惡意代碼,從而發生 XSS 攻擊。安全
比較常見的就是在論壇發帖、評論,而後在裏面注入惡意代碼,當用戶點擊帖子的時候,就會受到攻擊。
DOM型的 XSS 攻擊通常是攻擊者在注入惡意腳本後,修改頁面元素,獲取 DOM 的數據而後執行攻擊操做。好比將用戶的登陸表單的提交換成攻擊者的服務端,從而獲取用戶的登陸信息。
CSP 內容安全策略,主流瀏覽器都實現了 CSP。
配置內容安全策略涉及到添加 Content-Security-Policy HTTP頭部到一個頁面,並配置相應的值,以控制用戶代理(瀏覽器等)能夠爲該頁面獲取哪些資源。好比一個能夠上傳文件和顯示圖片頁面,應該容許圖片來自任何地方,但限制表單的action屬性只能夠賦值爲指定的端點。一個通過恰當設計的內容安全策略應該能夠有效的保護頁面免受跨站腳本攻擊。 (MDN)
經過設置 HttpOnly 防止 Cookie 被讀取。
前端對用戶的輸入進行檢查轉義,創建白名單,只容許安全的字符和 HTML 標籤存在:
const HTML_DECODE = { ' ': '\n', '<' : '<', '>' : '>', '&' : '&', '"': '"', ' ': ' ', '"': '\' // more code };
前端邏輯比較容易被繞過,因此後端也要對接收的數據進行檢查過濾,並在輸出或者拼接 HTML 的時候進行編碼、轉義。
CSRF,即 cross site request forgery,跨站請求僞造,能夠理解爲重放攻擊。比較常見的狀況是,攻擊者誘使用戶打開釣魚網站進行一些操做。
仍是舉一個例子來講明:假設某用戶登陸了www.a.com
網站,而後在沒有登出的狀況下打開了釣魚網站www.b.com
,而釣魚網站裏面有惡意腳本,在被打開的時候就帶着 Cookie 信息向www.a.com
發送了跨域請求。
對於重放攻擊,其實前端是沒什麼辦法進行處理的,主要靠後端。
Referer 字段
在 http 的請求頭裏,有一個 Referer 字段,記錄了 http 請求的來源地址,服務端經過檢查這個字段,判斷請求是否來自合法地址。但須要注意的是,Referer 字段是由瀏覽器來進行添加的,因此存在被篡改的可能。
驗證機制
一般 CSRF 是在用戶不知情的狀況下發送請求進行攻擊的,因此能夠利用驗證機制強制用戶與網站進行交互,例如發送驗證碼到用戶的手機、郵箱,或者須要用戶拼圖、填寫驗證碼等。但驗證機制對於用戶體驗不太好,並且並非全部操做都能加上驗證的。
token
服務端在用戶登陸後,簽發一個隨機的 token,能夠埋在頁面中,也能夠存儲在 sessionStorage 中,而後在客戶端設置攔截器,爲全部請求加上 token,服務端再設置攔截器,檢查請求是否擁有 token。由於同源策略(協議、域名、端口相同爲同源)的緣由,CSRF 並不能拿到 token。
let xhr = new XMLHttpRequest(); let token = sessionStorage.getItem('csrfToken'); xhr.setRequestHeader('CSRF-Token', token);
但須要注意的是, token 須要存儲在服務端,須要服務端進行讀取、驗證 token。