隨着大前端的快速發展,各種技術不斷更新,前端的安全問題也值得我們重視。今天我們來聊一聊前端常見的7個安全方面問題:
1.iframe
2.opener
3.CSRF(跨站請求偽造)
4.XSS(跨站腳本攻擊)
5.ClickJacking(點擊劫持)
6.HSTS(HTTP嚴格傳輸安全)
7.CND劫持
iframe
1.如何讓自己的網站不被其他網站使用iframe引用
if(top.location !== window.location){
top.location.href = xxx
}
當發現我們的網站被其他網站引用時,可以強制使網站跳轉到其他網站。
2.如何禁用,被使用的 iframe 對當前網站某些操作?
sandbox是html5的新屬性,主要是提高iframe安全系數。iframe因安全問題而臭名昭著,這主要是因為iframe常被用於嵌入到第三方中,然后執行某些惡意操作。
現在有一場景:我的網站需要 iframe 引用某網站,但是不想被該網站操作DOM、不想加載某些js(廣告、彈框等)、當前窗口被強行跳轉鏈接等,我們可以設置 sandbox 屬性。如使用多項用空格分隔。
- allow-same-origin:允許被視為同源,即可操作父級DOM或cookie等
- allow-top-navigation:允許當前iframe的引用網頁通過url跳轉鏈接或加載
- allow-forms:允許表單提交
- allow-scripts:允許執行腳本文件
- allow-popups:允許瀏覽器打開新窗口進行跳轉
“”:設置為空時上面所有允許全部禁止
opener
如果在項目中需要 打開新標簽 進行跳轉一般會有兩種方式:
// 1) HTML -> <a target='_blank' href='http://www.baidu.com'>
// 2) JS -> window.open('http://www.baidu.com')
/*
* 這兩種方式看起來沒有問題,但是存在漏洞。
* 通過這兩種方式打開的頁面可以使用 window.opener 來訪問源頁面的 window 對象。
* 場景:A 頁面通過 <a> 或 window.open 方式,打開 B 頁面。但是 B 頁面存在惡意代碼如下:
* window.opener.location.replace('https://www.baidu.com') 【此代碼僅針對打開新標簽有效】
* 此時,用戶正在瀏覽新標簽頁,但是原來網站的標簽頁已經被導航到了百度頁面。
* 惡意網站可以偽造一個足以欺騙用戶的頁面,使得進行惡意破壞。
* 即使在跨域狀態下 opener 仍可以調用 location.replace 方法。
*/
解決方案:
- 當使用a標簽跳轉時,
<a target="_blank" href="" rel="noopener noreferrer nofollow">a標簽跳轉url</a>
<!--
通過 rel 屬性進行控制:
noopener:會將 window.opener 置空,從而源標簽頁不會進行跳轉(存在瀏覽器兼容問題)
noreferrer:兼容老瀏覽器/火狐。禁用HTTP頭部Referer屬性(后端方式)。
nofollow:SEO權重優化,詳情見 https://blog.csdn.net/qq_33981438/article/details/80909881
-->
- 當使用window.open跳轉時,
<button onclick='openurl("http://www.baidu.com")'>click跳轉</button>
function openurl(url) {
var newTab = window.open();
newTab.opener = null;
newTab.location = url;
}
CSRF / XSRF(跨站請求偽造)
你可以這么理解 CSRF 攻擊:攻擊者盜用了你的身份,以你的名義進行惡意請求。它能做的事情有很多包括:以你的名義發送郵件、發信息、盜取賬號、購買商品、虛擬貨幣轉賬等。總結起來就是:個人隱私暴露及財產安全問題。
/*
* 闡述 CSRF 攻擊思想:(核心2和3)
* 1、瀏覽並登錄信任網站(舉例:淘寶)
* 2、登錄成功后在瀏覽器產生信息存儲(舉例:cookie)
* 3、用戶在沒有登出淘寶的情況下,訪問危險網站
* 4、危險網站中存在惡意代碼,代碼為發送一個惡意請求(舉例:購買商品/余額轉賬)
* 5、攜帶剛剛在瀏覽器產生的信息進行惡意請求
* 6、淘寶驗證請求為合法請求(區分不出是否是該用戶發送)
* 7、達到了惡意目標
*/
一般CSRF形式上有三種表現:
1.自動發起 Get 請求
模擬代碼如下:
1 <!DOCTYPE html>
<html>
<body>
<h1> 黑客的站點:CSRF 攻擊演示 </h1>
<img src="https://time.geekbang.org/sendcoin?user=hacker&number=100">
</body>
</html>
攻擊者將請求轉賬的鏈接隱藏在精美的圖片里,當你點擊時,就會想服務器發起請求。
2.自動發起 POST 請求
模擬代碼如下:
<!DOCTYPE html>
<html>
<body>
<h1> 黑客的站點:CSRF 攻擊演示 </h1>
<form id='hacker-form' action="https://time.geekbang.org/sendcoin" method="POST">
<input type="hidden" name="user" value="hacker" />
<input type="hidden" name="number" value="100" />
</form>
<script>
document.getElementById('hacker-form').submit();
</script>
</body>
</html>
在這段代碼中,我們可以看到黑客在他的頁面中構建了一個隱藏的表單,該表單的內容就是極客時間的轉賬接口。當用戶打開該站點之后,這個表單會被自動執行提交;當表單被提交之后,服務器就會執行轉賬操作。因此使用構建自動提交表單這種方式,就可以自動實現跨站點 POST 數據提交。
- 引誘用戶點擊鏈接
除了自動發起 Get 和 Post 請求之外,還有一種方式是誘惑用戶點擊黑客站點上的鏈接,這種方式通常出現在論壇或者惡意郵件上。黑客會采用很多方式去誘惑用戶點擊鏈接,示例代
碼如下所示:
<div>
<img width=150 src=http://images.xuejuzi.cn/1612/1_161230185104_1.jpg> </img>
<a href="https://time.geekbang.org/sendcoin?user=hacker&number=100" taget="_b 4 點擊下載美女照片</a>
</div>
這段黑客站點代碼,頁面上放了一張美女圖片,下面放了圖片下載地址,而這個下載地址實際上是黑客用來轉賬的接口,一旦用戶點擊了這個鏈接,那么他的極客幣就被轉到黑客賬戶上了。
解決方案:
- 利用好 Cookie 的 SameSite 屬性
在 HTTP 響應頭中,通過 set-cookie 字段設置 Cookie 時,可以帶上 SameSite 選項,如下:
set-cookie: 1P_JAR=2019-10-20-06; expires=Tue, 19-Nov-2019 06:36:21 GMT;SameSite=Strict;
SameSite 選項通常有 Strict、Lax 和 None 三個值。
Strict 最為嚴格。如果 SameSite 的值是 Strict,那么瀏覽器會完全禁止第三方Cookie。簡言之,如果你從極客時間的頁面中訪問 InfoQ 的資源,而 InfoQ 的某些Cookie 設置了 SameSite = Strict 的話
那么這些 Cookie 是不會被發送到 InfoQ 的服務器上的。只有你從 InfoQ 的站點去請求 InfoQ 的資源時,才會帶上這些 Cookie。
Lax 相對寬松一點。在跨站點的情況下,從第三方站點的鏈接打開和從第三方站點提交Get 方式的表單這兩種方式都會攜帶 Cookie。但如果在第三方站點中使用 Post 方法,或者通過 img、iframe 等標簽加載的 URL,
這些場景都不會攜帶 Cookie。
而如果使用 None 的話,在任何情況下都會發送 Cookie 數據。
-
驗證請求的來源站點
利用http請求頭中的referer或者origin字段告訴服務器請求來源,讓服務端判斷自否禁止該請求。
-
CSRF Token
除了使用以上兩種方式來防止 CSRF 攻擊之外,還可以采用 CSRF Token 來驗證,這個流程比較好理解,大致分為兩步:
第一步,在瀏覽器向服務器發起請求時,服務器生成一個 CSRF Token。CSRF Token 其實就是服務器生成的字符串,然后將該字符串植入到返回的頁面中。你可以參考下面示例代碼:
第二步,在瀏覽器端如果要發起轉賬的請求,那么需要帶上頁面中的 CSRF Token,然后服務器會驗證該 Token 是否合法。如果是從第三方站點發出的請求,那么將無法獲取到CSRF Token 的值,
所以即使發出了請求,服務器也會因為 CSRF Token 不正確而拒絕請求。
XSS/CSS(跨站腳本攻擊)
XSS 全稱是 Cross Site Scripting,為了與“CSS”區分開來,故簡稱 XSS,翻譯過來就是“跨站腳本”。XSS 攻擊是指黑客往 HTML 文件中或者 DOM 中注入惡意腳本,從而在
用戶瀏覽頁面時利用注入的惡意腳本對用戶實施攻擊的一種手段。
可以將XSS分為三種:存儲型XSS、反射型XSS以及基於dom的XSS。
存儲型 XSS 攻擊大致需要經過如下步驟:
1.首先黑客利用站點漏洞將一段惡意 JavaScript 代碼提交到網站的數據庫中;
2.然后用戶向網站請求包含了惡意 JavaScript 腳本的頁面;
3.當用戶瀏覽該頁面的時候,惡意腳本就會將用戶的 Cookie 信息等數據上傳到黑客服務器。
反射型XSS是指將可以script腳本插入用戶請求的url中,當請求被服務器處理后又反射回給用戶,web服務器並不會存儲這段script腳本。
基於 DOM 的 XSS 攻擊是不牽涉到頁面 Web 服務器的。具體來講,黑客通過各種手段將惡意腳本注入用戶的頁面中,比如通過網絡劫持在頁面傳輸過程中修改 HTML 頁面的內
容,這種劫持類型很多,有通過 WiFi 路由器劫持的,有通過本地惡意軟件來劫持的,它們的共同點是在 Web 資源傳輸過程或者在用戶使用頁面的過程中修改 Web 頁面的數據。
解決方案:
- 服務器對輸入腳本進行過濾或轉碼
不管是反射型還是存儲型 XSS 攻擊,我們都可以在服務器端將一些關鍵的字符進行轉碼,比如最典型的:
code:<script>alert('你被 xss 攻擊了')</script>
這段代碼過濾后,只留下了:
code:
這樣,當用戶再次請求該頁面時,由於script標簽的內容都被過濾了,所以這段腳本在客戶端是不可能被執行的。
除了過濾之外,服務器還可以對這些內容進行轉碼,還是上面那段代碼,經過轉碼之后,效果如下所示:
code:<script>alert(' 你被 xss 攻擊了 ')</script>
經過轉碼之后的內容,如script標簽被轉換為<script>,因此即使這段腳本返回給頁面,頁面也不會執行這段腳本。
-
充分利用 CSP
csp又叫內容安全策略,可以把它看做是一個白名單,告訴瀏覽器哪些第三方資源可以執行。 -
使用 HttpOnly 屬性
由於很多 XSS 攻擊都是來盜用 Cookie 的,因此還可以通過使用 HttpOnly 屬性來保護我們 Cookie 的安全。
通常服務器可以將某些 Cookie 設置為 HttpOnly 標志,HttpOnly 是服務器通過 HTTP 響應頭來設置的:
set-cookie: xxx;httpOnly;
ClickJacking(點擊劫持)
ClickJacking 翻譯過來被稱為點擊劫持。一般會利用透明 iframe 覆蓋原網頁誘導用戶進行某些操作達成目的。
解決方案:
- 在HTTP投中加入 X-FRAME-OPTIONS 屬性,此屬性控制頁面是否可被嵌入 iframe 中【DENY:不能被所有網站嵌套或加載;SAMEORIGIN:只能被同域網站嵌套或加載;ALLOW-FROM URL:可以被指定網站嵌套或加載。】
- 判斷當前網頁是否被 iframe 嵌套(詳情在第一條 firame 中)
HSTS(HTTP Strict Transport Security:HTTP嚴格傳輸安全)
網站接受從 HTTP 請求跳轉到 HTTPS 請求的做法,例如我們輸入“http://www.baidu.com”或“www.baidu.com”最終都會被302重定向到“https://www.baidu.com”。這就存在安全風險,當我們第一次通過 HTTP 或域名進行訪問時,302重定向有可能會被劫持,篡改成一個惡意或釣魚網站。
HSTS:通知瀏覽器此網站禁止使用 HTTP 方式加載,瀏覽器應該自動把所有嘗試使用 HTTP 的請求自動替換為 HTTPS 進行請求。用戶首次訪問時並不受 HSTS 保護,因為第一次還未形成鏈接。我們可以通過 瀏覽器預置HSTS域名列表 或 將HSTS信息加入到域名系統記錄中,來解決第一次訪問的問題。
CDN劫持
出於性能考慮,前端應用通常會把一些靜態資源存放到CDN(Content Delivery Networks)上面,例如 js 腳本和 style 文件。這么做可以顯著提高前端應用的訪問速度,但與此同時卻也隱含了一個新的安全風險。如果攻擊者劫持了CDN,或者對CDN中的資源進行了污染,攻擊者可以肆意篡改我們的前端頁面,對用戶實施攻擊。
現在的CDN以支持SRI為榮,script 和 link 標簽有了新的屬性 integrity,這個屬性是為了防止校驗資源完整性來判斷是否被篡改。它通過 驗證獲取文件的哈希值是否和你提供的哈希值一樣來判斷資源是否被篡改。
使用 SRI 需要兩個條件:一是要保證 資源同域 或開啟跨域,二是在script標簽中 提供簽名 以供校驗。
integrity 屬性分為兩個部分,第一部分是指定哈希值的生成算法(例:sha384),第二部分是經過編碼的實際哈希值,兩者之前用一個短橫(-)來分隔。
這個屬性也存在兼容問題:
ok,關於前端安全的問題就總結到這里。