前言
“安全”是個(gè)很大的話題耗绿,各種安全問題的類型也是種類繁多苹支。如果我們把安全問題按照所發(fā)生的區(qū)域來進(jìn)行分類的話,那么所有發(fā)生在后端服務(wù)器误阻、應(yīng)用债蜜、服務(wù)當(dāng)中的安全問題就是“后端安全問題”晴埂,所有發(fā)生在瀏覽器、單頁面應(yīng)用寻定、Web頁面當(dāng)中的安全問題則算是“前端安全問題”儒洛。
XSS
XSS是跨站腳本攻擊(Cross-Site Scripting)的簡(jiǎn)稱
XSS分為:存儲(chǔ)型和反射型
存儲(chǔ)型
存儲(chǔ)型XSS:存儲(chǔ)型XSS,持久化狼速,代碼是存儲(chǔ)在服務(wù)器中的琅锻,如在個(gè)人信息或發(fā)表文章等地方,加入代碼向胡,如果沒有過濾或過濾不嚴(yán)恼蓬,那么這些代碼將儲(chǔ)存到服務(wù)器中,用戶訪問該頁面的時(shí)候觸發(fā)代碼執(zhí)行僵芹。這種XSS比較危險(xiǎn)处硬,容易造成蠕蟲,盜竊cookie(雖然還有種DOM型XSS拇派,但是也還是包括在存儲(chǔ)型XSS內(nèi))郁油。
反射型
反射型XSS:非持久化,需要欺騙用戶自己去點(diǎn)擊鏈接才能觸發(fā)XSS代碼(服務(wù)器中沒有這樣的頁面和內(nèi)容)攀痊,一般容易出現(xiàn)在搜索頁面桐腌。
如何防御
防御XSS最佳的做法就是對(duì)數(shù)據(jù)進(jìn)行嚴(yán)格的輸出編碼,使得攻擊者提供的數(shù)據(jù)不再被瀏覽器認(rèn)為是腳本而被誤執(zhí)行苟径。
例如<script>在進(jìn)行HTML編碼后變成了<script>
而這段數(shù)據(jù)就會(huì)被瀏覽器認(rèn)為只是一段普通的字符串案站,而不會(huì)被當(dāng)做腳本執(zhí)行了。
你可以查閱OWASP XSS Prevention Cheat Sheet棘街,里面有關(guān)于XSS及其防御措施的詳細(xì)說明蟆盐。
iframe帶來的風(fēng)險(xiǎn)
風(fēng)險(xiǎn)
有些時(shí)候我們的前端頁面需要用到第三方提供的頁面組件,通常會(huì)以iframe的方式引入遭殉。典型的例子是使用iframe在頁面上添加第三方提供的廣告石挂、天氣預(yù)報(bào)、社交分享插件等等险污。
iframe在給我們的頁面帶來更多豐富的內(nèi)容和能力的同時(shí)痹愚,也帶來了不少的安全隱患。因?yàn)閕frame中的內(nèi)容是由第三方來提供的蛔糯,默認(rèn)情況下他們不受我們的控制拯腮,他們可以在iframe中運(yùn)行JavaScirpt腳本、Flash插件蚁飒、彈出對(duì)話框等等动壤,這可能會(huì)破壞前端用戶體驗(yàn)。
如果說iframe只是有可能會(huì)給用戶體驗(yàn)帶來影響淮逻,看似風(fēng)險(xiǎn)不大琼懊,那么如果iframe中的域名因?yàn)檫^期而被惡意攻擊者搶注阁簸,或者第三方被黑客攻破,iframe中的內(nèi)容被替換掉了哼丈,從而利用用戶瀏覽器中的安全漏洞下載安裝木馬启妹、惡意勒索軟件等等,這問題可就大了削祈。
如何防御
還好在HTML5中,iframe有了一個(gè)叫做sandbox的安全屬性脑漫,通過它可以對(duì)iframe的行為進(jìn)行各種限制髓抑,充分實(shí)現(xiàn)“最小權(quán)限“原則。使用sandbox的最簡(jiǎn)單的方式就是只在iframe元素中添加上這個(gè)關(guān)鍵詞就好优幸,就像下面這樣:
<iframe sandbox src="..."> ... </iframe>
sandbox還忠實(shí)的實(shí)現(xiàn)了“Secure By Default”原則吨拍,也就是說,如果你只是添加上這個(gè)屬性而保持屬性值為空网杆,那么瀏覽器將會(huì)對(duì)iframe實(shí)施史上最嚴(yán)厲的調(diào)控限制羹饰,基本上來講就是除了允許顯示靜態(tài)資源以外,其他什么都做不了碳却。比如不準(zhǔn)提交表單队秩、不準(zhǔn)彈窗、不準(zhǔn)執(zhí)行腳本等等昼浦,連Origin都會(huì)被強(qiáng)制重新分配一個(gè)唯一的值馍资,換句話講就是iframe中的頁面訪問它自己的服務(wù)器都會(huì)被算作跨域請(qǐng)求。
另外关噪,sandbox也提供了豐富的配置參數(shù)鸟蟹,我們可以進(jìn)行較為細(xì)粒度的控制。一些典型的參數(shù)如下:
allow-forms:允許iframe中提交form表單
allow-popups:允許iframe中彈出新的窗口或者標(biāo)簽頁(例如使兔,window.open()建钥,showModalDialog(),target=”_blank”等等)
allow-scripts:允許iframe中執(zhí)行JavaScript
allow-same-origin:允許iframe中的網(wǎng)頁開啟同源策略
更多詳細(xì)的資料虐沥,可以參考iframe中關(guān)于sandbox的介紹
請(qǐng)求劫持與HTTPS
請(qǐng)求劫持
DNS劫持
DNS劫持就是通過劫持了DNS服務(wù)器熊经,通過某些手段取得某域名的解析記錄控制權(quán),進(jìn)而修改此域名的解析結(jié)果欲险,導(dǎo)致對(duì)該域名的訪問由原IP地址轉(zhuǎn)入到修改后的指定IP奈搜,其結(jié)果就是對(duì)特定的網(wǎng)址不能訪問或訪問的是假網(wǎng)址,從而實(shí)現(xiàn)竊取資料或者破壞原有正常服務(wù)的目的盯荤。DNS劫持通過篡改DNS服務(wù)器上的數(shù)據(jù)返回給用戶一個(gè)錯(cuò)誤的查詢結(jié)果來實(shí)現(xiàn)的馋吗。 ??DNS劫持癥狀:在某些地區(qū)的用戶在成功連接寬帶后,首次打開任何頁面都指向ISP提供的“電信互聯(lián)星空”秋秤、“網(wǎng)通黃頁廣告”等內(nèi)容頁面宏粤。還有就是曾經(jīng)出現(xiàn)過用戶訪問Google域名的時(shí)候出現(xiàn)了百度的網(wǎng)站脚翘。這些都屬于DNS劫持。 再說簡(jiǎn)單點(diǎn)绍哎,當(dāng)你輸入google.com這個(gè)網(wǎng)址的時(shí)候来农,你看到的網(wǎng)站卻是百度的首頁。
http劫持:
在用戶的客戶端與其要訪問的服務(wù)器經(jīng)過網(wǎng)絡(luò)協(xié)議協(xié)調(diào)后崇堰,二者之間建立了一條專用的數(shù)據(jù)通道沃于,用戶端程序在系統(tǒng)中開放指定網(wǎng)絡(luò)端口用于接收數(shù)據(jù)報(bào)文,服務(wù)器端將全部數(shù)據(jù)按指定網(wǎng)絡(luò)協(xié)議規(guī)則進(jìn)行分解打包海诲,形成連續(xù)數(shù)據(jù)報(bào)文繁莹。 ??用戶端接收到全部報(bào)文后,按照協(xié)議標(biāo)準(zhǔn)來解包組合獲得完整的網(wǎng)絡(luò)數(shù)據(jù)特幔。其中傳輸過程中的每一個(gè)數(shù)據(jù)包都有特定的標(biāo)簽咨演,表示其來源、攜帶的數(shù)據(jù)屬性以及要到何處蚯斯,所有的數(shù)據(jù)包經(jīng)過網(wǎng)絡(luò)路徑中ISP的路由器傳輸接力后薄风,最終到達(dá)目的地,也就是客戶端拍嵌。 ??HTTP劫持是在使用者與其目的網(wǎng)絡(luò)服務(wù)所建立的專用數(shù)據(jù)通道中遭赂,監(jiān)視特定數(shù)據(jù)信息,提示當(dāng)滿足設(shè)定的條件時(shí)横辆,就會(huì)在正常的數(shù)據(jù)流中插入精心設(shè)計(jì)的網(wǎng)絡(luò)數(shù)據(jù)報(bào)文嵌牺,目的是讓用戶端程序解釋“錯(cuò)誤”的數(shù)據(jù),并以彈出新窗口的形式在使用者界面展示宣傳性廣告或者直接顯示某網(wǎng)站的內(nèi)容龄糊。列入本地的fiddler為一種劫持
請(qǐng)求劫持唯一可行的預(yù)防方法就是盡量使用HTTPS協(xié)議訪問逆粹。
公鑰和私鑰
什么是https,這里不再解釋了炫惩,簡(jiǎn)單理解就是通過SSL(Secure Sockets Layer)層來加密http數(shù)據(jù)來進(jìn)行安全傳輸僻弹。 那使用HTTPS是怎樣進(jìn)行安全數(shù)據(jù)傳輸?shù)模?/p>
先看個(gè)有意思的問題:
A、B兩個(gè)人分別在兩個(gè)島上他嚷,并且分別有一個(gè)箱子蹋绽,一把鎖,和打開這把鎖的鑰匙(A的鑰匙打不開B手上的鎖筋蓖,B的鑰匙也打不開A的鎖)卸耘。此時(shí)A要跟B互通情報(bào),此時(shí)需要借助C的船運(yùn)輸粘咖,C是一個(gè)不可靠的人蚣抗,如果A直接把情報(bào)送給B或把情報(bào)放在箱子里給B,都可能會(huì)被C偷走瓮下;如果A把情報(bào)鎖在箱子里翰铡,B沒有打開A鎖的鑰匙無法獲得情報(bào)內(nèi)容钝域。請(qǐng)問有什么辦法可以盡可能快的讓A和B互通情報(bào)。
這就是公鑰和私鑰的問題了锭魔,答案比較簡(jiǎn)單例证,也對(duì)應(yīng)了公鑰和私鑰在https中的應(yīng)用過程。
公鑰(Public Key)與私鑰(Private Key)是通過一種算法得到的一個(gè)密鑰對(duì)(即一個(gè)公鑰和一個(gè)私鑰)迷捧,公鑰是密鑰對(duì)中公開的部分织咧,私鑰則是非公開的部分。公鑰通常用于加密會(huì)話密鑰漠秋、驗(yàn)證數(shù)字簽名笙蒙,或加密可以用相應(yīng)的私鑰解密的數(shù)據(jù)。通過這種算法得到的密鑰對(duì)能保證在世界范圍內(nèi)是唯一的膛堤。使用這個(gè)密鑰對(duì)的時(shí)候手趣,如果用其中一個(gè)密鑰加密一段數(shù)據(jù)晌该,必須用另一個(gè)密鑰解密肥荔。比如用公鑰加密數(shù)據(jù)就必須用私鑰解密,如果用私鑰加密也必須用公鑰解密朝群,否則解密將不會(huì)成功燕耿。
Https的通信過程
1、客戶端發(fā)送https請(qǐng)求姜胖,告訴服務(wù)器發(fā)將建立https連接
2誉帅、服務(wù)器將服務(wù)端生成的公鑰返回給客戶端,如果是第一次請(qǐng)求將告訴客戶端需要驗(yàn)證鏈接
3右莱、客戶端接收到請(qǐng)求后’client finished’報(bào)文串通過獲取到的服務(wù)器公鑰加密發(fā)送給服務(wù)器蚜锨,并將客戶端生成的公鑰也發(fā)送給服務(wù)器
4、服務(wù)器獲取到加密的報(bào)文和客戶端公鑰慢蜓,先使用服務(wù)器私鑰解密報(bào)文亚再,然后將報(bào)文通過客戶端的公鑰加密返回給客戶端。
5晨抡、客戶端通過私鑰解密報(bào)文氛悬,判斷是否為自己開始發(fā)送的報(bào)文串;如果正確耘柱,說明安全連接驗(yàn)證成功如捅,將數(shù)據(jù)通過服務(wù)器公鑰加密不斷發(fā)送給服務(wù)器,服務(wù)器也不斷解密獲取報(bào)文调煎,并通過客戶端公鑰加密返回給客戶端驗(yàn)證镜遣。這樣就建立了不斷通信的連接。
Https協(xié)議頭解析
以打開 https://github.com/ 的過程為例士袄,請(qǐng)求通用頭部如下
Request URL:https://github.com/ouvens\n
Request Method:GET
Status Code:200 OK (from cache)
Remote Address:192.30.252.131:443
Response Headers
其它瀏覽器web安全控制
X-XSS-Protection
這個(gè)header主要是用來防止瀏覽器中的反射性xss×忆蹋現(xiàn)在朴肺,只有IE,chrome和safari(webkit)支持這個(gè)header坚洽。
正確的設(shè)置:
X-XSS-Protection:1; mode=block
0 – 關(guān)閉對(duì)瀏覽器的xss防護(hù)
1 – 開啟xss防護(hù)
1; mode=block – 開啟xss防護(hù)并通知瀏覽器阻止而不是過濾用戶注入的腳本戈稿。
1; report=http://site.com/report – 這個(gè)只有chrome和webkit內(nèi)核的瀏覽器支持,這種模式告訴瀏覽器當(dāng)發(fā)現(xiàn)疑似xss攻擊的時(shí)候就將這部分?jǐn)?shù)據(jù)post到指定地址讶舰。 通常不正確的設(shè)置
X-Content-Type-Options
&ems;?這個(gè)header主要用來防止在IE9鞍盗、chrome和safari中的MIME類型混淆攻擊。firefox目前對(duì)此還存在爭(zhēng)議跳昼。通常瀏覽器可以通過嗅探內(nèi)容本身的方法來決定它是什么類型般甲,而不是看響應(yīng)中的content-type值。通過設(shè)置 X-Content-Type-Options:如果content-type和期望的類型匹配鹅颊,則不需要嗅探敷存,只能從外部加載確定類型的資源。舉個(gè)例子堪伍,如果加載了一個(gè)樣式表锚烦,那么資源的MIME類型只能是text/css,對(duì)于IE中的腳本資源帝雇,以下的內(nèi)容類型是有效的:
application/ecmascript
application/javascript
application/x-javascript
text/ecmascript
text/javascript
text/jscript
text/x-javascript
text/vbs
text/vbscript
對(duì)于chrome涮俄,則支持下面的MIME 類型:
text/javascript
text/ecmascript
application/javascript
application/ecmascript
application/x-javascript
text/javascript1.1
text/javascript1.2
text/javascript1.3
text/jscript
text/live script
nosniff – 這個(gè)是唯一正確的設(shè)置,必須這樣尸闸。
Strict-Transport-Security
Strict Transport Security (STS) 是用來配置瀏覽器和服務(wù)器之間安全的通信彻亲。它主要是用來防止中間人攻擊,因?yàn)樗鼜?qiáng)制所有的通信都走TLS吮廉。目前IE還不支持 STS頭苞尝。需要注意的是,在普通的http請(qǐng)求中配置STS是沒有作用的宦芦,因?yàn)楣粽吆苋菀拙湍芨倪@些值宙址。為了防止這樣的現(xiàn)象發(fā)生,很多瀏覽器內(nèi)置了一個(gè)配置了STS的站點(diǎn)list踪旷。
正確的設(shè)置 : 注意下面的值必須在https中才有效曼氛,如果是在http中配置會(huì)沒有效果。
max-age=31536000 – 告訴瀏覽器將域名緩存到STS list里面令野,時(shí)間是一年舀患。
max-age=31536000; includeSubDomains – 告訴瀏覽器將域名緩存到STS list里面并且包含所有的子域名,時(shí)間是一年气破。
max-age=0 – 告訴瀏覽器移除在STS緩存里的域名聊浅,或者不保存此域名。
通常不正確的設(shè)置
判斷一個(gè)主機(jī)是否在你的STS緩存中,chrome可以通過訪問chrome://net-internals/#hsts低匙,首先旷痕,通過域名請(qǐng)求選項(xiàng)來確認(rèn)此域名是否在你的STS緩存中。然后顽冶,通過https訪問這個(gè)網(wǎng)站欺抗,嘗試再次請(qǐng)求返回的STS頭,來決定是否添加正確强重。
.Content-Security-Policy
CSP是一種由開發(fā)者定義的安全性政策性申明绞呈,通過CSP所約束的的規(guī)責(zé)指定可信的內(nèi)容來源(這里的內(nèi)容可以指腳本、圖片间景、iframe佃声、fton、style等等可能的遠(yuǎn)程的資源)倘要。通過CSP協(xié)定圾亏,讓W(xué)EB能夠加載指定安全域名下的資源文件,保證運(yùn)行時(shí)處于一個(gè)安全的運(yùn)行環(huán)境中封拧。
正確配置:
Content-Security-Policy:default-src *; base-uri 'self'; block-all-mixed-content; child-src 'self' render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-src 'self' render.githubusercontent.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.gravatar.com *.wp.com *.githubusercontent.com; media-src 'none'; object-src assets-cdn.github.com; plugin-types application/x-shockwave-flash; script-src assets-cdn.github.com; style-src 'self' 'unsafe-inline' assets-cdn.github.com
X-Frame-Options
這個(gè)header主要用來配置哪些網(wǎng)站可以通過frame來加載資源志鹃。它主要是用來防止UI redressing 補(bǔ)償樣式攻擊。IE8和firefox 18以后的版本都開始支持ALLOW-FROM哮缺。chrome和safari都不支持ALLOW-FROM弄跌,但是WebKit已經(jīng)在研究這個(gè)了加叁。
正確的設(shè)置
X-Frame-Options: deny
deny – 禁止所有的資源(本地或遠(yuǎn)程)試圖通過frame來加載其他也支持X-Frame-Options 的資源缝裁。
sameorigion – 只允許遵守同源策略的資源(和站點(diǎn)同源)通過frame加載那些受保護(hù)的資源跌造。
allow-from http://www.example.com – 允許指定的資源(必須帶上協(xié)議http或者h(yuǎn)ttps)通過frame來加載受保護(hù)的資源。這個(gè)配置只在IE和firefox下面有效糠溜。其他瀏覽器則默認(rèn)允許任何源的資源(在X-Frame-Options沒設(shè)置的情況下)。
Access-Control-Allow-Origin
Access-Control-Allow-Origin是從Cross Origin Resource Sharing (CORS)中分離出來的直撤。這個(gè)header是決定哪些網(wǎng)站可以訪問資源非竿,通過定義一個(gè)通配符來決定是單一的網(wǎng)站還是所有網(wǎng)站可以訪問我們的資源。需要注意的是谋竖,如果定義了通配符红柱,那么 Access-Control-Allow-Credentials選項(xiàng)就無效了,而且user-agent的cookies不會(huì)在請(qǐng)求里發(fā)送蓖乘。
正確的設(shè)置
Access-Control-Allow-Origin : *
*– 通配符允許任何遠(yuǎn)程資源來訪問含有Access-Control-Allow-Origin 的內(nèi)容锤悄。
http://www.example.com – 只允許特定站點(diǎn)才能訪問(http://[host], 或者 https://[host])
Public-Key-Pins
公鑰固定(Public Key Pinning)是指一個(gè)證書鏈中必須包含一個(gè)白名單中的公鑰,也就是說只有被列入白名單的證書簽發(fā)機(jī)構(gòu)(CA)才能為某個(gè)域名*.example.com簽發(fā)證書嘉抒,而不是你的瀏覽器中所存儲(chǔ)的任何 CA 都可以為之簽發(fā)零聚。可以理解為https的證書域名白名單。 ??Public-Key-Pins (PKP)的目的主要是允許網(wǎng)站經(jīng)營者提供一個(gè)哈希過的公共密鑰存儲(chǔ)在用戶的瀏覽器緩存里隶症。跟Strict-Transport-Security功能相似的是政模,它能保護(hù)用戶免遭中間人攻擊。這個(gè)header可能包含多層的哈希運(yùn)算蚂会,比如pin-sha256=base64(sha256(SPKI))淋样,具體是先將 X.509 證書下的Subject Public Key Info (SPKI) 做sha256哈希運(yùn)算,然后再做base64編碼胁住。然而习蓬,這些規(guī)定有可能更改,例如有人指出措嵌,在引號(hào)中封裝哈希是無效的躲叼,而且在33版本的chrome中也不會(huì)保存pkp的哈希到緩存中。
這個(gè)header和 STS的作用很像企巢,因?yàn)樗?guī)定了最大子域名的數(shù)量枫慷。此外,pkp還提供了一個(gè)Public-Key-Pins-Report-Only 頭用來報(bào)告異常浪规,但是不會(huì)強(qiáng)制阻塞證書信息或听。當(dāng)然,這些chrome都是不支持的笋婿。
參考
https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html
https://www.veracode.com/blog/2014/03/guidelines-for-setting-security-headers/
原文鏈接 http://jixianqianduan.com/frontend-weboptimize/2016/03/20/web-security-and-https.html