隨着Web和移動應用等的快速發展,越來越多的Web安全問題逐漸顯示出來。一個網站或一個移動應用,如果沒有做好相關的安全防范工作,不僅會造成用戶信息、服務器或數據庫信息的泄露,更可能會造成用戶財產的損失,因此Web安全問題需要引起廣大開發者的重視。接下來的幾篇文章中,將會對Web常見的一些攻擊以及相關的防范方法進行詳細的介紹。
系列文章:
- Web前端安全之安全編碼原則
- Web前端安全之跨站腳本攻擊(XSS)
- Web前端安全之跨站請求偽造(CSRF)
- Web前端安全之點擊劫持
- Web前端安全之文件上傳漏洞
- Web前端安全之任意URL跳轉漏洞
本文主要介紹了Web前端開發中需要遵守的一些安全編碼原則,將會對Web安全以及安全編碼原則進行介紹,歡迎大家交流討論~
1. Web安全
在學習常用的Web安全編碼原則以及掌握常見的攻擊防范方法之前,我們有必要先了解一下什么是Web安全,以及我們面臨的Web漏洞或攻擊通常有哪些。
1.1 什么是Web安全
隨着Web2.0、社交網絡和移動應用等產品的誕生,越來越多的信息都被放到互聯網應用上展示,而Web的快速發展也引起了黑客們的強烈關注。黑客們通常會利用操作系統或Web存在的漏洞,對各種各樣的互聯網應用發起攻擊,輕則篡改網頁內容,重則盜取重要內部數據,並使得應用訪問者受到侵害。因此,作為Web應用的開發者,我們需要了解網站或應用中可能存在的漏洞,並且對各種可能遭到的攻擊提前做好防范。
1.2 Web常見的漏洞
在前端面試中,我們可能經常會被面試官問到這個問題,“從在瀏覽器地址欄輸入url到頁面展示在我們面前,這個過程中發生了什么?",相信很多同學都能夠很快回答上來。但是如果面試官問,"從在瀏覽器地址欄輸入url到頁面展示在我們面前,這個過程可能存在哪些漏洞或者會遭到哪些攻擊?”,可能就會難住很多同學了。下面給出了一個圖,展示了Web中常見的一些漏洞。

總的來說,我們在開發Web網站或應用的過程中,可能面臨的Web安全威脅或漏洞包括以下這些:
- XSS跨站腳本攻擊
- CSRF漏洞
- 點擊劫持
- 文件上傳漏洞
- 任意URL跳轉漏洞
- SQL注入
- 命令注入
- XXE漏洞
- SSRF漏洞
- 邏輯漏洞
- 信息泄露
- ......
面對這么多漏洞或攻擊,我們能夠做的,就是在進行架構設計或功能開發時,就應當全面考慮用戶、APP/瀏覽器、后台服務器以及各層通訊之間可能存在的安全問題,並且開展安全防護設計,提前做好防范工作。
由於筆者是前端開發,因此也會重點關注前端的內容,也就是和前端較為相關的漏洞。接下來,將會對前端開發中常用的一些安全編碼原則進行介紹,並且在后續的文章中,也會對上述漏洞中的前5個漏洞的攻擊和防范進行詳細的介紹。
2. 安全編碼原則
接下來,將會介紹一些常用的安全編碼方法,幫助我們編寫符合安全規范的代碼。
2.1 登錄注冊安全
當用戶想要訪問我們網站或應用時,通常需要做的第一步就是進行注冊和登錄。而實現登錄注冊功能時如果沒有做好安全防范,很可能會造成用戶賬戶密碼信息被盜取。因此,下面主要總結了在實現登錄注冊功能時需要注意的一些安全要點。
(1)注冊時賬戶密碼要求
注冊時需要限制用戶名合法字符和長度,密碼需要禁止使用弱口令,密碼長度應當大於8位且包含大小寫字母,數字及特殊字符。
(2)登錄失敗時提示要求
登錄失敗時不應返回詳細提示用戶名不存在,防止猜解用戶名。
(3)增加驗證碼機制
單個用戶口令失敗3次后應有驗證碼機制出現,驗證碼每校驗過一次應當立即失效防止驗證碼重用。
(4)不在常用地登錄時需要增加身份驗證
當用戶登錄成功時,后台應該記錄用戶的用戶名、IP和時間,當嘗試登錄IP不在歷史常登錄IP地理位置時,應進行多因素二次驗證用戶身份,防止用戶因密碼泄露被盜取賬戶。
(5)Cookie安全
Cookie中通常會包含用戶的登錄態標識,因此為了保障Cookie的安全,需要設置HttpOnly屬性以防止被XSS漏洞/JavaScript操縱泄露。此外,實現全站HTTPS后,Cookie應當設置secure屬性,使得瀏覽器僅在安全加密連接時才能傳送使用該Cookie。
2.2 訪問控制
當用戶成功到登錄網站或應用之后,接下來就可以開始訪問相關的頁面。但是我們的系統中通常包含不同身份的用戶,比如有超級管理員、普通管理員、教師和學生等身份等,而不同身份的用戶可以訪問的頁面應該是不一樣的,因此我們還需要做好訪問控制。
(1)權限控制
無論是Web頁面還是對外的HTTP API接口,在系統設計之初就需要考慮身份驗證和權限校驗機制。除了官網靜態頁或新聞頁等公開頁面之外,當用戶訪問其它頁面時,都需要添加權限校驗機制,僅有權限的用戶才能訪問相應的服務和數據,防止水平越權和垂直越權。
如下面代碼所示,給出了使用Vue進行權限控制的一個例子,我們可以通過添加全局攔截路由,在用戶進入頁面前先對用戶身份進行判斷,如果該用戶有權限,才讓用戶訪問對應頁面。
router.beforeEach(async (to, from, next) => { // 先判斷用戶是否登錄 checkIfLogin(); // 若用戶登錄成功,需要拉取該用戶的信息 getUserInfo(); // 上面兩個步驟完成之后,需要判斷用戶的權限 if (userInfo.role === 1 || userInfo.role === 2) { next(); // 跳轉到用戶想要訪問的頁面 } else { alert('您沒有權限訪問該頁面); next('/'); // 跳轉到默認頁面 } });
2.3 輸出轉義
經過登錄以及訪問權限的校驗,用戶就可以訪問到他們想看的頁面了。而如Web網站的頁面通常是需要經過瀏覽器的渲染才能最終顯示在用戶面前,但是在這個過程中,可能也會被黑客注入如XSS的攻擊,因此對於輸出到網頁上的數據我們也需要進行安全防護,也就是對頁面上的數據輸出進行轉義編碼。
(1)轉義編碼
使用HtmlEncode轉義特殊字符,比如將“>","<",單引號或雙引號等特殊字符進行轉義,可以避免從HTML節點內容、HTML屬性或JavaScript注入而產生的XSS攻擊。下面給出了一個例子,可以實現特殊字符的轉義。
const htmlEncode = function (handleString){ return handleString .replace(/&/g,"&") .replace(/</g,"<") .replace(/>/g,">") .replace(/ /g," ") .replace(/\'/g,"'") .replace(/\"/g,"""); }
2.4 輸入限制
除了輸出的轉義編碼之外,對於一些需要用戶提交信息的地方如表單,我們也需要對用戶的輸入進行校驗和過濾,防止攻擊者通過利用XSS等漏洞向服務器或數據庫注入惡意腳本。
(1)輸入校驗
對於不可信的輸入來源都需要進行數據校驗,從而判斷用戶的輸入是否符合預期的數據類型、長度和數據范圍。有效的輸入驗證一般需要基於以下兩點原則:
- 采用正則表達式(正則表達式應該限制^開頭和$結尾,以免部分匹配而被繞過)
- 采用白名單思想,因為用戶的輸入集合是無限的,如果僅僅從黑名單進行過濾,會存在被繞過的可能性。所以應將用戶的輸入類型、字符集合和長度限制在安全范圍之內。
下面給出了常用的一些字段的正則表達式校驗防范。
日期:日期格式通常為:2018-12-21,2018-12-21 11:34:22,2017/12/21,2017/12/21 11:33:22,正則表達式參考如下。
(^\d{4}[-/]\d{2}[-/]\d{2}$)|(^\d{4}[-/]\d{2}[-
/]\d{2}\s+\d{2}\:\d{2}($|\:\d{2}$))
域名:域名都由英文字母和數字組成,每一個標號不超過63個字符,也不區分大小寫字母。標號中除連字符(-)外不能使用其它的標點符號,完整域名不超過255個字符,正則表達式參考如下。
^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-
9]{0,62})+(.)?$
郵箱地址:Email地址由"@"號分成郵箱名和網址兩部分,其中郵箱名由單詞字符、大小寫字母、數字及下划線組成,並且可以出現"."號,正則表達式參考如下。
^[.0-9a-zA-Z_]{1,18}@([0-9a-zA-Z-]{1,13}\.){1,}[a-zA-Z]{1,3}$
用戶名:用戶名通常允許大小寫字母、數字和下划線組成,最小6位最大12位的長度,正則表達式參考如下。
^[0-9a-zA-Z_]{6,12}$
手機號:國內手機格式為1開頭的數字,長度為11位。
^1\d{10}$
當然,除了我們自己手動編寫正則表達式對用戶輸入進行驗證之外,現在一些常用的UI框架如Element UI,這些框架提供的表單控件,已經具備了自動校驗的功能。
(2)數據過濾
除了對用戶輸入的數據進行數據類型等的校驗外,對於用戶提交的數據,還需要結合業務場景,對可能造成SQL注入、XSS和命令注入中常見的危險字符如"<",">","%”和"&"等字符進行過濾。
2.5 文件上傳安全
文件上傳現在也是用戶在訪問網站或應用時經常進行的一個操作,為了防止用戶上傳惡意文件,我們在實現文件上傳功能時,也需要考慮下面這些原則。
(1)身份驗證
文件上傳前可以增加驗證用戶身份的步驟。
(2)文件校驗
根據業務場景需要,必須采用白名單形式校驗文件上傳的文件類型,同時還需要驗證文件的后綴名,並且限制合適的文件大小。
(3)文件存儲
文件應保存在Ceph、對象存儲或NoSQL等環境,若保存在Web容器內可能會產生WebShell風險被入侵。
此外,如果使用了第三方存儲服務如騰訊雲COS進行文件存儲時,需要注意權限配置檢查,避免由於使用默認配置而導致的文件可直接遍歷泄露等問題。
2.6 數據傳輸安全
數據在網絡的傳輸過程中,攻擊者通過一些手段,可能可以獲取到傳輸中的數據信息。因此,在數據的傳輸過程中,我們也有必要保證數據傳輸的安全。
(1)采用POST方法發送請求
增、刪、改操作必須使用POST方法提交。
(2)采用HTTPS
所有的頁面和HTTP API接口都通過HTTPS進行,用HTTPS代替HTTP,當用戶以HTTP訪問時,可以設置自動跳轉到HTTPS。
(3)加密算法選擇
如果在通信過程中涉及到使用加密算法,在選擇加密算法時,對稱加密算法可以使用AES-128以上,公鑰加密可以使用RSA-2048以上,哈希算法采用SHA-2以上。
2.7 數據保護
在一些業務場景中,我們可以需要將某些信息存儲在客戶端或LocalStorage中,因此我們也應該加強對用戶數據的保護,防止用戶信息或隱私泄露。
(1)不在客戶端存儲敏感信息
不要在客戶端或LocalStorage上明文保存密碼或其它敏感信息。
(2)數據脫敏或加密
涉及個人隱私的敏感信息須加密存儲並且脫敏后顯示給用戶。
(3)請求校驗
用於標記資源的ID參數不能是數序數字以防止被遍歷,對訪問資源ID的每個請求做權限校驗。
3. 總結
在上面的文章中,首先主要先介紹了什么是Web安全以及常見的Web漏洞,並且在后續的介紹中對平時開發中需要注意的一些安全編碼原則進行了介紹。
總的來說,在進行編碼時,我們不能太過信任用戶的輸入,凡是用戶的輸入需要渲染到頁面的地方都需要進行轉義和過濾,並在信息提交前做好校驗。此外,還需要充分考慮到數據的傳輸安全和存儲安全,並且做好權限的訪問控制。接下來就讓我們記住安全編碼原則,開始編寫符合安全規范的代碼吧。
