Cross-Site Scripting(跨站腳本攻擊)簡稱 XSS,是一種代碼注入攻擊。攻擊者經過在目標網站上注入惡意腳本,使之在用戶的瀏覽器上運行。利用這些惡意腳本,攻擊者可獲取用戶的敏感信息如 Cookie、SessionID 等,進而危害數據安全。php
爲了區分CSS,改成XSS。html
XSS 的本質是:惡意代碼未通過濾,與網站正常的代碼混在一塊兒;瀏覽器沒法分辨哪些腳本是可信的,致使惡意腳本被執行。前端
根據攻擊的來源,XSS 攻擊可分爲存儲型、反射型和 DOM 型三種。數據庫
類型 | 存儲區 | 插入點 |
---|---|---|
存儲型 XSS | 後端數據庫 | HTML |
反射型 XSS | URL | HTML |
DOM 型 XSS | 後端數據庫/前端存儲/URL | 前端 JavaScript |
存儲區:惡意代碼存放的位置。後端
插入點:由誰取得惡意代碼,並插入到網頁上。瀏覽器
這種攻擊常見於帶有用戶保存數據的網站功能,如論壇發帖、商品評論、用戶私信等。安全
反射型 XSS 跟存儲型 XSS 的區別是:存儲型 XSS 的惡意代碼存在數據庫裏,反射型 XSS 的惡意代碼存在 URL 裏。bash
反射型 XSS 漏洞常見於經過 URL 傳遞參數的功能,如網站搜索、跳轉等。服務器
因爲須要用戶主動打開惡意的 URL 才能生效,攻擊者每每會結合多種手段誘導用戶點擊。cookie
POST 的內容也能夠觸發反射型 XSS,只不過其觸發條件比較苛刻(須要構造表單提交頁面,並引導用戶點擊),因此很是少見。
DOM 型 XSS 跟前兩種 XSS 的區別:DOM 型 XSS 攻擊中,取出和執行惡意代碼由瀏覽器端完成,屬於前端 JavaScript 自身的安全漏洞,而其餘兩種 XSS 都屬於服務端的安全漏洞。
輸入側過濾可以在某些狀況下解決特定的 XSS 問題,但會引入很大的不肯定性和亂碼問題。在防範 XSS 攻擊時應避免此類方法。
存儲型和反射型 XSS 都是在服務端取出惡意代碼後,插入到響應 HTML 裏的,攻擊者刻意編寫的「數據」被內嵌到「代碼」中,被瀏覽器所執行。
預防這兩種漏洞,有兩種常見作法:
1.改爲純前端渲染,把代碼和數據分隔開。
2.對 HTML 作充分轉義。
純前端渲染
1.瀏覽器先加載一個靜態 HTML,此 HTML 中不包含任何跟業務相關的數據。
2.而後瀏覽器執行 HTML 中的 JavaScript。
3.JavaScript 經過 Ajax 加載業務數據,調用 DOM API 更新到頁面上。
在純前端渲染中,咱們會明確的告訴瀏覽器:下面要設置的內容是文本(.innerText),仍是屬性(.setAttribute),仍是樣式(.style)等等。瀏覽器不會被輕易的被欺騙,執行預期外的代碼了。
轉義HTML
若是拼接 HTML 是必要的,就須要採用合適的轉義庫,對 HTML 模板各處插入點進行充分的轉義。
經常使用的模板引擎,如 doT.js、ejs、FreeMarker 等,對於 HTML 轉義一般只有一個規則,就是把 & < > " ' / 這幾個字符轉義掉,確實能起到必定的 XSS 防禦做用,但並不完善:
XSS 安全漏洞 | 簡單轉義是否有防禦做用 |
---|---|
HTML 標籤文字內容 | 有 |
HTML 屬性值 | 有 |
CSS 內聯樣式 | 無 |
內聯 JavaScript | 無 |
內聯 JSON | 無 |
跳轉連接 | 無 |
DOM 型 XSS 攻擊,實際上就是網站前端 JavaScript 代碼自己不夠嚴謹,把不可信的數據看成代碼執行了。
在使用 .innerHTML、.outerHTML、document.write() 時要特別當心,不要把不可信的數據做爲 HTML 插到頁面上,而應儘可能使用 .textContent、.setAttribute() 等。
若是用 Vue/React 技術棧,而且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 階段避免 innerHTML、outerHTML 的 XSS 隱患。
DOM 中的內聯事件監聽器,如 location、onclick、onerror、onload、onmouseover 等, 標籤的 href 屬性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串做爲代碼運行。若是不可信的數據拼接到字符串中傳遞給這些 API,很容易產生安全隱患,請務必避免。
禁止加載外域代碼,防止複雜的攻擊邏輯。
禁止外域提交,網站被攻擊後,用戶的數據不會泄露到外域。
禁止內聯腳本執行(規則較嚴格,目前發現 GitHub 使用)。
禁止未受權的腳本執行(新特性,Google Map 移動版在使用)。
合理使用上報能夠及時發現 XSS,利於儘快修復問題。
複製代碼
對於不受信任的輸入,都應該限定一個合理的長度。雖然沒法徹底防止 XSS 發生,但能夠增長 XSS 攻擊的難度
HTTP-only Cookie: 禁止 JavaScript 讀取某些敏感 Cookie,攻擊者完成 XSS 注入後也沒法竊取此 Cookie。
驗證碼:防止腳本冒充用戶提交危險操做。
CSRF(Cross-site request forgery)跨站請求僞造:攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送跨站請求。利用受害者在被攻擊網站已經獲取的註冊憑證,繞事後臺的用戶驗證,達到冒充用戶對被攻擊的網站執行某項操做的目的。
<img src="http://bank.example/withdraw?amount=10000&for=hacker" >
複製代碼
<form action="http://bank.example/withdraw" method=POST>
<input type="hidden" name="account" value="xiaoming" />
<input type="hidden" name="amount" value="10000" />
<input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script>
複製代碼
訪問該頁面,表單會自動提交。
連接類型的CSRF並不常見,比起其餘兩種用戶打開頁面就中招的狀況,這種須要用戶點擊連接纔會觸發。這種類型一般是在論壇中發佈的圖片中嵌入惡意連接,或者以廣告的形式誘導用戶中招,攻擊者一般會以比較誇張的詞語誘騙用戶點擊,例如:
<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
重磅消息!!
<a/>
複製代碼
既然CSRF大多來自第三方網站,那麼咱們就直接禁止外域(或者不受信任的域名)對咱們發起請求。
* Origin Header
* Referer Header
複製代碼
用戶打開頁面的時候,服務器給這個用戶生成一Token,但不能放到cookie中,不然仍是會被攻擊者冒用。因此要存在服務器的session中
大型網站,使用session存儲CSRF Token會帶來很大壓力。並且如今都是分佈式部署,一個用戶發送的屢次HTTP請求可能不在一臺服務器上,可能會獲取不到session數據,所以分佈式集羣中CSRF Token存儲在Redis之類的公共存儲空間
使用Session存儲,讀取和驗證Token會引發比較大的複雜度和性能問題。
這種方法的Token是一個計算出來的結果,而非隨機生成的字符串。這樣在校驗時無需再去讀取存儲的Token,只用再次計算一次便可。
那麼另外一種防護措施是使用雙重提交Cookie。利用CSRF攻擊不能獲取到用戶Cookie的特色,咱們能夠要求Ajax和表單請求攜帶一個Cookie中的值。
優勢
無需使用Session,適用面更廣,易於實施。
Token儲存於客戶端中,不會給服務器帶來壓力。
相對於Token,實施成本更低,能夠在先後端統一攔截校驗,而不須要一個個接口和頁面添加。
缺點
Cookie中增長了額外的字段。
若是有其餘漏洞(例如XSS),攻擊者能夠注入Cookie,那麼該防護方式失效。
難以作到子域名的隔離。
爲了確保Cookie傳輸安全,採用這種防護方式的最好確保用整站HTTPS的方式,若是還沒切HTTPS的使用這種方式也會有風險。
Samesite=Strict
這種稱爲嚴格模式,代表這個 Cookie 在任何狀況下都不可能做爲第三方 Cookie,絕無例外
Set-Cookie: foo=1; Samesite=Strict
Set-Cookie: bar=2; Samesite=Lax
Set-Cookie: baz=3
複製代碼
咱們在 a.com 下發起對 b.com 的任意請求,foo 這個 Cookie 都不會被包含在 Cookie 請求頭中,但 bar 會。舉個實際的例子就是,假如淘寶網站用來識別用戶登陸與否的 Cookie 被設置成了 Samesite=Strict,那麼用戶從百度搜索頁面甚至天貓頁面的連接點擊進入淘寶後,淘寶都不會是登陸狀態,由於淘寶的服務器不會接受到那個 Cookie,其它網站發起的對淘寶的任意請求都不會帶上那個 Cookie。
Samesite=Lax
這種稱爲寬鬆模式,比 Strict 放寬了點限制:假如這個請求是這種請求(改變了當前頁面或者打開了新頁面)且同時是個GET請求,則這個Cookie能夠做爲第三方Cookie。
注意
另一個問題是Samesite的兼容性不是很好,現階段除了重新版Chrome和Firefox支持之外,Safari以及iOS Safari都還不支持,現階段看來暫時還不能普及。
並且,SamesiteCookie目前有一個致命的缺陷:不支持子域。例如,種在topic.a.com下的Cookie,並不能使用a.com下種植的SamesiteCookie。這就致使了當咱們網站有多個子域名時,不能使用SamesiteCookie在主域名存儲用戶登陸信息。每一個子域名都須要用戶從新登陸一次。
僅用於我的整理,參考: