Web前端安全之安全編碼原則

Yellow_ice發表於2021-10-20

    隨著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,"&amp;")     
  .replace(/</g,"&lt;")     
  .replace(/>/g,"&gt;")     
  .replace(/ /g,"&nbsp;")     
  .replace(/\'/g,"&#39;")     
  .replace(/\"/g,"&quot;");
}

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漏洞,並且在後續的介紹中對平時開發中需要注意的一些安全編碼原則進行了介紹。

    總的來說,在進行編碼時,我們不能太過信任使用者的輸入,凡是使用者的輸入需要渲染到頁面的地方都需要進行轉義和過濾,並在資訊提交前做好校驗。此外,還需要充分考慮到資料的傳輸安全和儲存安全,並且做好許可權的訪問控制。接下來就讓我們記住安全編碼原則,開始編寫符合安全規範的程式碼吧。

    

 

相關文章