前端安全編碼規範
前言
隨著網際網路高速的發展,資訊保安已經成為企業重點關注焦點之一,而前端又是引發安全問題的高危據點,所以,作為一個前端開發人員,需要了解前端的安全問題,以及如何去預防、修復安全漏洞。
下面就以前端可能受到的攻擊方式為起點,講解web中可能存在的安全漏洞以及如何去檢測這些安全漏洞,如何去防範潛在的惡意攻擊。
1. 跨站指令碼攻擊(Cross Sites Script)
跨站指令碼攻擊
,Cross Site Script(簡稱 CSS或)。指黑客通過“HTML注入
”篡改了網頁,插入了惡意的指令碼(主要是JavaScript指令碼
),從而在使用者瀏覽網頁時,控制使用者瀏覽器的一種攻擊。
瞭解了什麼是XSS,那你一定想知道,它有什麼危害以及如何去防禦
這裡羅列一張列表:
- 掛馬
- 盜取使用者Cookie。
- 釣魚攻擊,高階的釣魚技巧。
- 刪除目標文章、惡意篡改資料、嫁禍。
- 劫持使用者Web行為,甚至進一步滲透內網。
- 爆發Web2.0蠕蟲。
- 蠕蟲式掛馬攻擊、刷廣告、刷瀏量、破壞網上資料
- 其它安全問題
常見的跨站指令碼攻擊也可分為:反射型XSS、儲存型XSS、DOM Based XSS
下面針對這三種常見的型別做具體的分析
1.1 反射型XSS--也可被稱為是HTML注入
反射型XSS,也稱為"非持久型XSS"簡單的把使用者輸入的資料"反射"給瀏覽器,即黑客往往需要誘使使用者"點選"一個惡意連結攻擊才能成功,使用者通過點選這個惡意連結,攻擊者可以成功獲取使用者隱私資料的一種方式。如:"盜取使用者Cookie資訊"、"破壞頁面結構"、"重定向到其他網站",盜取內網IP等。
那麼既然反射型XSS也可以是HTML注入,那麼它注入的關鍵自然也就從前端的HTML頁面開始下手:
1. 使用者能夠與瀏覽器頁面產生互動動作(輸入搜尋的關鍵詞,點選按鈕,點選連結等等),但這些都需要去誘使使用者去操作,說起來容易,做起來難。
2. 使用者輸入的資料會被攻擊方拼接出合適的html去執行惡意的js指令碼,這樣的過程就像是"一次反射"
1.2 儲存型XSS
儲存型XSS,也稱為"`持久型XSS`",它與`反射型XSS`不同之處在於,它會將使用者輸入的資料"儲存"在攻擊方的伺服器上,具有很強的"穩定性"。
例如:訪問某黑客寫下的一篇含有惡意JavaScript程式碼的部落格文章,黑客把惡意指令碼儲存到服務端。
1.3 DOM based XSS
從效果上來說,也是"反射型XSS",單獨劃分出來,是因為其形成是通過修改頁面的"DOM節點"形成的XSS。
例如:通過修改DOM節點上的繫結方法,使用者無意間通過點選、輸入等行為執行這些方法獲取到使用者的相關資訊
1.4 如何去檢測是否存在XSS
一般方法是,使用者可以在有關鍵字輸入搜尋的地方輸入<script>alert(123)</script>
後點選搜尋,若彈框出現展示123,說明存在XSS漏洞,這就說明前端並沒有對使用者輸入的內容過濾處理。
1.5 XSS的攻擊方式
1.Cookie劫持
通過偽裝一些`圖片和按鈕`等,誘使使用者對其操作,使網頁執行了攻擊者的惡意指令碼,使攻擊者能夠獲取當前使用者的Cookie資訊
2.構造GET和POST請求
若某攻擊者想刪除某網站的一篇文章,首先獲得當前文章的id,然後通過使用指令碼`插入圖片`傳送一個`GET請求`,或`構造表單`,`XMLHTTPRequest`傳送`POST請求`以達到刪除該文章的目的
3.XSS釣魚
`釣魚`這個詞一般認識是起源於`社會工程學`,黑客使用這個這門學科的理念思想,在未授權不知情的情況下誘騙使用者,並得到對方對方的姓名、年齡、郵箱賬號、甚至是銀行卡密碼等私人資訊。
比如:"某使用者在某網站(已被攻擊)上操作黑客偽造的一個登入框,當使用者在登入框中輸入了使用者名稱(這裡可能是身份證號等)和密碼之後,將其資訊上傳至黑客的伺服器上(該使用者的資訊就已經從該網站洩漏)"
4.獲取使用者真實的IP地址
通過第三方軟體獲取,比如客戶端安裝了Java環境(JRE),則可通過呼叫`Java Applet`的介面獲取客戶端本地的IP地址
1.6 XSS的防禦方式
1.HttpOnly
原理:瀏覽器禁止頁面的Javascript訪問帶有HttpOnly屬性的cookie。(實質解決的是:XSS後的cookie劫持攻擊)如今已成為一種“標準”的做法
解決方案:
JavaEE給Cookie新增HttpOnly的方式為:
response.setHeader("Set-Cookie","cookiename=value; Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");
2.輸入檢查(XSS Filter)
原理:讓一些基於特殊字元的攻擊失效。(常見的Web漏洞如XSS、SQLInjection等,都要求攻擊者構造一些特殊字元)
* 輸入檢查的邏輯,必須在服務端實現,因為客戶端的檢查也是很容易被攻擊者繞過,現有的普遍做法是兩端都做同樣的檢查,客戶端的檢查可以阻擋大部分誤操作的正常使用者,從而節約伺服器的資源。
解決方案:
檢查是否包含"JavaScript","<script></script>"等敏感字元。以及對字串中的<>:"&/'等特殊字元做處理
3.輸出檢查
原理:一般來說除了富文字輸出之外,在變數輸出到HTML頁面時,使用編碼或轉義的方式來防禦XSS攻擊
解決方案:
* 針對HTML程式碼的編碼方式:HtmlEncode
* PHP:htmlentities()和htmlspecialchars()兩個函式
* Javascript:JavascriptEncode(需要使用""對特殊字元進行轉義,同時要求輸出的變數必須在引號內部)
* 在URL的path(路徑)或者search(引數)中輸出,使用URLEncode
4.更嚴格的做法
除了數字和字母外的所有字元,都使用十六進位制的方式進行編碼
2. 跨站點請求偽造(Cross Sites Request Forgery)
跨站點請求偽造,指利用使用者身份操作使用者賬戶的一種攻擊方式,即攻擊者誘使使用者訪問一個頁面,就以該使用者身份在第三方有害站點中執行了一次操作,洩露了使用者的身份資訊,接著攻擊者就可以使用這個偽造的,但真實存在的身份資訊,到某網站冒充使用者執行惡意操作。
但是,攻擊者只有預測到URL的所有引數與引數值,才能成功地偽造一個請求(當然了,他可以在安全站點裡以自己的身份實際去操作一下,還是能拿到引數的);反之,攻擊者無法攻擊成功
下圖通俗解釋什麼是CSRF
,又是如何給使用者帶來危害的
參考上圖,我們可以總結,完成一次CSRF攻擊,必須滿足兩個條件
- 使用者登入受信任網站A,並且在本地生成Cookie
- 在不登出網站A的情況下,訪問有害網站B
2.1 CSRF的原理
CSRF攻擊是攻擊者利用**`使用者身份`**操作使用者賬戶的一種攻擊方式
如電影速度與激情5中吉賽爾使用內褲獲取巴西大佬指紋,最後成功使用偽造指紋的手法開啟保險櫃,CSRF只不過是網路上這個手法的實現。
2.2 CSRF的攻擊方式
1.瀏覽器的Cookie策略
瀏覽器所持有的策略一般分為兩種:
Session Cookie,臨時Cookie。儲存在瀏覽器程式的記憶體中,瀏覽器關閉了即失效。
Third-party Cookie,本地Cookie。伺服器在Set-Cookie時指定了Expire Time。過期了本地Cookie失效,則網站會要求使用者重新登入。
* 在瀏覽網站的過程中,即使瀏覽器開啟了Tab頁,Session Cookie都是有效的,因此發起CSRF攻擊是可行的。
2.P3P頭的副作用
"P3P Header"是 "W3C" 制定的一項關於隱私的標準,全稱是 "The Platform for Privacy Preference"(隱私偏好平臺)
如果網站返回給瀏覽器的 HTTP 頭包含有 P3P 頭,則在某種程度上來說,將允許 瀏覽器傳送第三方 Cookie。在 IE 下即使是"<iframe>"、`<script>`等標籤頁將不再攔截第三方 Cookie 的傳送。主要應用在類似廣告等需要跨域訪問的頁面。
3.GET,POST請求
* 這裡有個誤區
大多數 CSRF 攻擊,都是通過 <img> 、 <iframe> 、 <script> 等帶 src 屬性的標籤,這類標籤只能傳送一次 GET 請求,而不能傳送 POST 請求,由此也有了認為 CSRF 攻擊只能由 GET 請求發起的錯誤觀點。
構造一個 POST 請求,只需要在一個不可見的iframe視窗中,構造一個form表單,然後使用JavaScript自動提交這個表單。那麼整個自動提交表單的過程,對於使用者來說就是不可見的。
2.3 CSRF的防禦方式
1.驗證碼
原理:
CSRF攻擊過程中,使用者在不知情的情況下構造了網路請求,新增驗證碼後,強制使用者必須與應用進行互動
* 優點:簡潔而有效
* 缺點:網站不能給所有的操作都加上驗證碼
2.Referer Check
原理:
* 利用HTTP頭中的Referer判斷請求來源是否合法
* Referer首部包含了當前請求頁面的來源頁面的地址,一般情況下Referer的來源頁就是發起請求的那個頁面,如果是在iframe中發起的請求,那麼對應的頁面URL就是iframe的src
* 優點:簡單易操作(只需要在最後給所有安全敏感的請求統一新增一個攔截器來檢查Referer的值就行)
* 缺點:伺服器並非什麼時候都能取到Referer
1.很多出於保護使用者隱私的考慮,限制了Referer的傳送。
2.比如從HTTPS跳轉到HTTP,出於安全的考慮,瀏覽器不會傳送Referer
3.使用Anti CSRF Token
原理:把引數加密,或者使用一些隨機數,從而讓攻擊者無法猜測到引數值,也就無法構造請求的 URL,也就無法發起 CSRF 攻擊。
例子(增加token):
* 比如一個刪除操作的URL是:`http://host/path/delete?uesrname=abc&item=123`
* 保持原引數不變,新增一個引數Token,Token值是隨機的,不可預測
* http://host/path/delete?username=abc&item=123&token=[random(seed)]
* 優點:比檢查Referer方法更安全,並且不涉及使用者隱私
* 缺點:
加密
1. 加密後的URL非常難讀,對使用者非常不友好
2. 加密的引數每次都在改變,導致使用者無法對頁面進行搜尋
3. 普通引數也會被加密或雜湊,將會給DBA工作帶來很大的困擾,因為資料分析常常需要用到引數的明文
token
1. 對所有的請求都新增Token比較困難
需要注意的點
- Token需要足夠隨機,必須用足夠安全的隨機數生成演算法
- Token應該為使用者和伺服器所共同持有,不能被第三方知曉
- Token可以放在使用者的Session或者瀏覽器的Cookie中
- 儘量把Token放在表單中,把敏感操作由GET改為POST,以form表單的形式提交,可以避免Token洩露(比如一個頁面:
http://host/path/manage?username=abc&token=[random]
,在此頁面使用者需要在這個頁面提交表單或者單擊“刪除”按鈕,才能完成刪除操作,在這種場景下,如果這個頁面包含了一張攻擊者能指定地址的圖片<img src="http://evil.com/notexist" />
,則這個頁面地址會作為HTTP請求的Refer傳送到evil.com的伺服器上,從而導致Token洩露)
2.4 XSRF
當網站同時存在XSS和CSRF漏洞時,XSS可以模擬客戶端瀏覽器執行任意操作,在XSS攻擊下,攻擊者完全可以請求頁面後,讀取頁面內容中的Token值,然後再構造出一個合法的請求
3. 點選劫持(ClickJacking)
點選劫持是一種視覺上的欺騙手段。攻擊者使用一個透明的、不可見的iframe,覆蓋在一個網頁上,然後誘使使用者在網頁上進行操作,此時使用者將在不知情的情況下點選透明的iframe頁面。通過調整iframe頁面的位置,可以誘使使用者恰好點選在iframe頁面的一些功能性按鈕上。
比如,程式設計師小王在訪問A網頁時,點選空白區域,瀏覽器卻意外開啟了xx新葡京賭場的頁面,於是他在A網頁開啟控制檯,在空白區域發現了一個透明的iframe,該iframe嵌入了一個第三方網頁的URL
3.1 點選劫持防禦方式
1.X-Frame-Options HTTP響應頭是用來給瀏覽器指示允許一個頁面能否在`<frame>、<iframe>、<object>`中展現的標記
#### 有三個可選的值
1. DENY:瀏覽器會拒絕當前頁面載入任何frame頁面(即使是相同域名的頁面也不允許)
2. SAMEORIGIN:允許載入frame頁面,但是frame頁面的地址只能為同源域名下的頁面
3. ALLOW-FROM:可以載入指定來源的frame頁面(可以定義frame頁面的地址)
2.禁止iframe的巢狀
if(window.top.location !== window.loaction){window.top.location === window.self.location}
4. 其他安全問題
4.1 跨域問題處理
當服務端設定 'Access-Control-Allow-Origin' 時使用了萬用字元 "*",允許來自任意域的跨域請求,這是極其危險的
4.2 postMessage 跨視窗傳遞資訊
postMessage 允許每一個 window(包括當前視窗、彈出視窗、iframes等)物件往其他的視窗傳送文字訊息,從而實現跨視窗的訊息傳遞。並且這個功能不受同源策略限制。
必要時,在接受視窗驗證 Domain,甚至驗證URL,以防止來自非法頁面的訊息。實際上是在程式碼上實現一次同源策略的驗證過程。接受視窗對介面的資訊進行安全檢查。
4.3 Web Storage
Web Storage 分為 Session Storage 和 Local Storage。
雖然受同源策略的約束,但當存有敏感資訊時,也可能會成為攻擊的目標。
5. 總結
- 謹慎使用者輸入資訊,進行輸入檢查(客戶端和服務端同時檢查)
- 在變數輸出到HTML頁面時,都應該進行編碼或轉義來預防XSS攻擊
- 該用驗證碼的時候一定要添上
- 儘量在重要請求上新增Token引數,注意Token要足夠隨機,用足夠安全的隨機數生成演算法