72 個網絡應用安全實操要點,全方位保護 Web 應用的安全

這是我參與更文挑戰的第 4 天,活動詳情查看: 更文挑戰html

原文地址:Web Application Security Checklist前端

原文做者:Teo Selenius(已受權)java

譯者 & 校訂:HelloGitHub-小熊熊 & 滷蛋git

對於開發者而言,網絡安全的重要性不言而喻。任何一處代碼錯誤、一個依賴項漏洞或是數據庫的端口暴露到公網,都會有可能直接送你上熱搜。github

那麼,哪裏能夠找到詳細的避雷指引呢?OWASP's top 10 清單過短了,並且它更關注的是漏洞羅列,而非對預防。相比之下,ASVS 是個很好的列表,但仍是知足不了實際需求。web

本文這份清單將介紹 72 個實操要點,讓你全方位保護你的 Web 應用程序。各位看官,準備入坑啦!shell

1、瀏覽器端的威脅防護

一、用且僅用 HTTPS,防範網絡攻擊

衆所周知,一個安全的應用須要對瀏覽器和 Web 服務器之間的全部鏈接進行加密。此外,建議禁用一些舊的密碼套件和協議。 使用 HTTPS 時,僅加密網站的「敏感」部分是不夠的。如非這樣,攻擊者能夠截獲某個未加密的 HTTP 請求,而後僞造來自服務器的響應,返回惡意內容。 幸運的是,HTTPS 目前是很容易作到的。咱們能夠經過 Let's Encrypt 免費得到證書,加上 CertBot 免費續期。數據庫

繼續咱們的清單,下一個是 HSTS 它與 HTTPS 密切相關。json

二、使用 HSTS 和預加載來保護用戶免受 SSL 剝離攻擊

服務器能夠用 HSTS 或 Strict Transport Security header 來強制進行加密鏈接。它表示須要一直使用 HTTPS 鏈接訪問網站。後端

HSTS 能夠防止 SSL 剝離攻擊。所謂的 SSL 剝離攻擊也就是:網絡上的攻擊者截獲瀏覽器發出的第一個 HTTP 請求(一般是未加密的),並當即僞造對該請求的回覆,僞裝是服務器並將鏈接降級爲明文 HTTP。

值得注意的是,HSTS 僅在用戶至少成功訪問了一次應用程序的狀況下才能生效。爲了克服這個限制,能夠把咱們的網站提交到 hstspreload.org ,這樣,各瀏覽器即可以將咱們的域名經過硬編碼寫入到 HSTS 列表中。

以下:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
複製代碼

警告:

在實施 HSTS 時,將會強制進出該網站的全部網絡請求均被加密,若是網站請求中仍然有純文本,可能沒法訪問。因此,先設置一個小的 max-age 參數進行調試,若是一切正常工做,再加大這個值。調試成功後再加上預加載 (preload) ,把開啓預加載保留在最後一步,由於關閉它是件很麻煩和痛苦的事情。

三、設置安全 Cookie,保護用戶免受網絡攻擊

給 Cookie 加上 Secure 屬性。此屬性將防止 Cookie 在(意外或強制的)未加密的鏈接中泄漏。

Set-Cookie: foo=bar; ...other options... Secure
複製代碼

四、安全生成 HTML 以免 XSS 漏洞

要避免 XSS(跨站點腳本)漏洞,能夠採用下面兩種方法:

  1. 徹底靜態的網站(例如 JavaScript SPA + 後端API)。避免生成 HTML 問題的最有效方法是根本不生成HTML,如前述方法,固然,也能夠試試很酷的 NexJS。
  2. 模板引擎。針對傳統的 Web 應用程序,其中的 HTML 大可能是在後端服務器上根據提供參數動態生成的。這種狀況下,不要經過字符串鏈接來建立 HTML 。推薦的作法是使用模板引擎,好比 PHP 語言的 Twig、Java 語言的 Thymeleaf、Python 語言的 Jinja2 等等。

此外,務必要正確配置模板引擎,從而能夠自動對參數進行編碼,而且不要使用任何能夠繞過這種編碼的「不安全」函數。不要把 HTML 放在回調函數、屬性(不帶引號)或 href/src 等諸如此類的地方。

五、安全使用 JavaScript 以免 XSS 漏洞

要避免 JavaScript 端的 XSS(跨站點腳本)漏洞,切忌將不受信任的數據傳遞到可執行代碼的函數或屬性中。這類常見的函數或屬性包括:

  • eval、setTimeout、setInterval 等。
  • innerHTML,React's dangerouslySetInnerHTML 等。
  • onClick、onMouseEnter、onError 等。
  • href、src 等。
  • location, location.href 等。

六、沙箱處理不可信內容,避免 XSS 漏洞

最好是能避免不可信的內容,但每每又不能徹底避免:例如須要從遠程獲取 HTML 進行展現,或者須要容許用戶用所見即所得的編輯器寫文章,等等。

要避免這些場景中的 XSS(跨站點腳本)漏洞,請首先使用 DOMPurify 清理內容,而後在沙箱中進行內容呈現。

即便所見即所得的編輯庫聲稱從 HTML 中移除了惡意內容,仍然能夠經過從新淨化和沙箱來處理,進一步確保安全。

還有一種常見的狀況是,咱們想在網頁展現廣告等內容。這種狀況下簡單採用 IFrame 是不夠的,由於 same-origin 策略會容許跨域的 frame 將父級 frame (也就是咱們的網站)的 URL 修改成一個釣魚網站。所以,要記住使用 IFrame 的沙箱屬性來避免此種狀況的發生。

七、採用內容安全策略,避免 XSS 漏洞

內容安全策略(CSP)能夠很好地防護 XSS(跨站點腳本)攻擊、點擊劫持攻擊等。因此,必定要用它!默認狀況下,CSP 會阻止幾乎全部的危險操做,因此額外的配置越少越好。以下:

Content-Security-Policy: default-src 'self'; form-action 'self'; object-src 'none'
複製代碼

它容許從 Web 應用程序的源代碼加載腳本、樣式、圖像、字體等,但不容許加載其餘內容。最值得注意的是,它將阻止內聯腳本()的運行,從而更好地預防 XSS 漏洞。

此外,form-action:'self' 指令可防止在網站上建立惡意 HTML 表單(好比「您的會話已過時,請在此處輸入密碼」相似的表單),並將其提交到攻擊者的服務器。

不管如何,都不要指定 script-src: unsafe inline ,一旦這樣作,CSP 將形同虛設。

最後,若是你擔憂 CSP 會影響生產環境,能夠先以 Report-Only 模式進行部署:

Content-Security-Policy-Report-Only: default-src 'self'; form-action 'self'
複製代碼

八、設置 HttpOnly 的 Cookie,保護用戶免受 XSS 攻擊

爲 Cookie 設置 HttpOnly 屬性,能夠防止 Cookie 被 JavaScript 代碼訪問。 一旦跨腳本攻擊發生,該設置也會讓黑客更難竊取到 Cookie 信息。固然,有些須要被 JavaScript 代碼訪問的 Cookie,就不能作這個設置了。

Set-Cookie: foo=bar; ...other options... HttpOnly
複製代碼

九、針對下載功能,合理設置避免 XSS 漏洞

向用戶提供下載功能時,在 header 中設置 Content-Disposition: attachment,從而避免 XSS 漏洞。該設置將禁止在用戶瀏覽器直接渲染文件,從而避免 HTML 或 SVG 格式的下載文件可能引起的漏洞。以下:

Content-Disposition: attachment; filename="document.pdf"
複製代碼

假如咱們想容許特定的文件(如 pdf)能在瀏覽器端打開,而且也肯定這樣是安全的,那麼,能夠針對該類型文件,將 header 省略掉或是將 attachment 換爲 inline。

十、針對 API 響應,合理設置避免 XSS 漏洞

反射型文件下載(RFD)攻擊每每經過構建一個 URL 從 API 下載一個惡意文件來實現。針對該類漏洞,可採用在 API HTTP 響應中返回帶有安全文件名的 Content-Disposition header來防護。

十一、利用現有平臺的反跨站請求僞造(CSRF)機制,避免 CSRF 漏洞

爲避免反跨站請求僞造漏洞,務必確保咱們所採用的平臺開啓了反跨站請求僞造功能,並確保該配置發揮了應有的做用。

十二、驗證 OAuth 身份認證的 state 參數,避免 CSRF 漏洞

有一類與 OAuth 身份認證相關的跨站請求僞造漏洞是黑客讓用戶不經意間採用其帳戶進行登陸。所以,若是有使用 OAuth 身份認證,務必確保對狀態(state)參數的驗證。

1三、正確使用 HTTP 協議,避免 CSRF 漏洞

除了 POST、PUT、PATCH、DELETE 之外,不要使用其它 HTTP 方法進行數據更改。GET 請求通常是不包含在反跨站請求僞造機制中的。

1四、爲 Cookie 設置同源屬性,避免 CSRF、XS-leak、XSS 漏洞

爲 Cookie 設置 SameSite 屬性。SameSite 能防止大多數的跨站點請求僞造攻擊,並且還能夠防止許多跨站點泄漏的漏洞。

SameSite 屬性有兩種模式:寬鬆(lax)和嚴格(strict)。

寬鬆模式能夠防止大多數跨站點計時和跨站點請求僞造攻擊,但對基於 Get 請求的跨站點請求僞造漏洞無效。以下:

Set-Cookie: foo=bar; ...other options... SameSite=Lax
複製代碼

嚴格模式則能夠防止該類基於 Get 請求的漏洞,以及反射型的跨站點腳本漏洞。然而,嚴格模式不適合常規的應用程序,由於它會中斷身份驗證連接。若是用戶已登陸某個網站,如今要在新的頁面打開指向該應用程序的連接,則打開的新頁面將不會爲該用戶自動登陸。因爲嚴格模式的限制,會話 Cookie 也不會隨請求一塊兒發送。嚴格模式設置以下:

Set-Cookie: foo=bar; ...other options... SameSite=Strict
複製代碼

1五、每次登陸建立一個新的會話 ID,防止會話固定攻擊

會話固定攻擊通常是在如下情形發生:

  1. 攻擊者將 Cookie(例如 JSESSIONID=ABC123)注入到用戶的瀏覽器中。不用擔憂,攻擊者有不少方法能夠作到這一點。

  2. 用戶使用其憑據登陸,並在登陸請求中提交攻擊者設置的 JSESSIONID=ABC123 。

  3. 應用程序對 Cookie 和用戶進行身份驗證。

  4. 與此同時,擁有該 Cookie 的攻擊者也就能夠經過該用戶的身份進行登陸了。

爲了防止出現這種狀況,程序中須要在身份驗證經過後,建立一個新的會話 ID 返回給用戶,而不是驗證可能被動了手腳的 Cookie。

1六、合理命名 Cookie,防止會話固定攻擊

難道 Cookie 命名也能影響到網絡應用程序的安全性?確實如此!將 Cookie 採用 __Host-** 的形式來命名,瀏覽器將:

  • 不能經過非加密的連接訪問該項 Cookie, 從而避免會話固定攻擊以及其它涉及到 Cookie 讀取與寫入的攻擊;
  • 不容許子域名重寫該項 Cookie,從而避免來自子域名網站(抑或是被攻陷,抑或自己就是惡意的)的攻擊。

該項設置示例以下:

Set-Cookie: __Host-foo=bar ...other options...
複製代碼

1七、設置 Cache-Control header,防止用戶信息被竊取

緩存是將訪問過的網站、下載過的文件所有存儲在硬盤的某個位置,直到有人手動刪除它們。默認狀況下,瀏覽器會對頁面的一切內容進行緩存,從而加快訪問速度、節約網絡帶寬。

要在公共網絡環境保證信息安全,咱們須要將全部 HTTP 響應設置一個合適的 Cache-Control header,特別是針對非公開的和動態的內容。

該項設置示例以下:

Cache-Control: no-store, max-age=0
複製代碼

1八、設置 Clear-Site-Data header,防止用戶信息被竊取

另一個能夠有效保證用戶退出後記錄即被清除的 header 是 Clear-Site-Data 。當用戶退出登陸時,能夠在 HTTP 請求中攜帶該 header。瀏覽器會清除該域名下的緩存、Cookie、存儲以及執行上下文。大部分瀏覽器都支持該 header。

該項設置示例以下:

Clear-Site-Data: "*"
複製代碼

1九、穩當地處理「退出」,防止用戶信息被竊取

用戶退出登陸後,務必要對訪問令牌和會話識別碼進行失效處理。這樣,即便攻擊者從訪問歷史/緩存/內存等地方獲取到這些信息,它們也再也不有效。

此外,若是有單點登陸,切記要調用單點登陸的退出端口。不然,由於單點登陸會話仍處於活躍狀態,此時的退出將會無效,只要用戶再次點擊「登陸」,便可自動登陸。

最後,清理掉你可能用到過的 Cookie、HTML5 存儲等。上面提到的 Clear-Site-Data 還未被某些瀏覽器支持,因此最好仍是手工清除一下。

20、針對 JavaScript 密碼採用 SessionStorage,防止用戶信息被後來者竊取

SessionStorage 相似於 LocalStorage,但對每一個標籤頁都是獨有的,並且在瀏覽器/標籤頁關閉之後將自動清除。

注意:若是要在系統內打開的多個標籤頁之間同步用戶的受權信息,那就須要用事件來同步 sessionStorage 信息。

2一、不要經過 URL 傳輸敏感信息

URL 設計的初衷就不是爲了傳輸敏感信息。它會被顯示在屏幕上,存儲到瀏覽器歷史記錄,也容易隨 referrer header 而泄漏,被記錄在服務器日誌等。因此,切忌在 URL 中傳遞敏感信息。

2二、採用 Referrer 策略,防止 URL 地址泄露

默認狀況下,當從系統中連接到一個外部網站時,瀏覽器會設置一個 Referrer 的 header 來告訴該網站這次訪問的來源。這個 header 包含了整個 URL 地址,這可能就涉及到一點隱私。

能夠在 HTTP 響應中設置一個 Referrer-Policy 的 header 來禁止該默認行爲:

Referrer-Policy: no-referrer
複製代碼

2三、爲應用設置獨立域名,防止同源應用相互干擾

若是咱們這樣設置應用域名:www.example.com/app1/www.example.com/app2/,是很是危險…

所以,咱們須要給每一個應用一個獨立的域名。因此,這種狀況下應該設置爲:https://app1.example.com/https://app2.example.com/

注意:位於同一個域名下的子域名是能夠爲整個域名設置 Cookie 的。例如 app1.example.com 能夠爲 example.com 設置 Cookie,而這個 Cookie 也將適用於 app2.example.com。容許爲一個站點設置 Cookie 有時會給會話固定等類型的漏洞以可乘之機。公共後綴列表能夠用來應對該問題。此外,也能夠經過將 Cookie 命名爲 __Host- 來防止其被子域名所覆蓋。

2四、謹慎採用 CORS(跨域資源共享)

瀏覽器的安全模型大部分是依賴於同源策略,它能夠防止應用的跨域讀取。而 CORS(跨域資源共享)則是一種容許網站進行跨域資源訪問的手段。因此,決定使用它以前,最好先搞清楚本身是否真的須要。

2五、限制請求來源

若是你在 api.example.com 的服務須要被來自 www.example.com 的 GET 請求訪問,那麼能夠在 api.example.com 服務上指定以下header:

Access-Control-Allow-Origin: https://www.example.com
複製代碼

若是你有個公開的服務接口(好比說一個提供給互聯網上 JavaScript 客戶端使用的計算器服務),那麼你能夠指定一個隨機的來源:

Access-Control-Allow-Origin: *
複製代碼

若是你只想讓有限的幾個域名訪問它,那麼能夠在程序中讀取請求的 Origin header,進行比對後處理。不過,建議使用現成的庫來操做,不要徒手擼,很容易出錯。

2六、謹慎使用 allow credentials 選項

默認狀況下,跨域資源共享是不帶用戶憑證的。但若是在 Web 服務器端指定以下 header,則將容許攜帶:

Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
複製代碼

這對 header 組合至關危險。由於它會使跨域訪問具有已登陸用戶的權限,並使用該權限來訪問網站資源。因此,若是你不得不使用它,務必當心爲上。

2七、對 HTTP method 進行驗證

僅容許所須要的 HTTP 方法,從而最小化攻擊面。

Access-Control-Allow-Methods: GET
複製代碼

2八、合理使用 WebSockets, 避免反跨站請求僞造等漏洞

WebSockets 迄今仍是比較新的技術,技術文檔較少使用它不免會有些風險。因此,採用時務必要作到如下幾點:

  • 對鏈接進行加密

    就像咱們應該用 https:// 而非 http:// 採用 WebSockets 時也要使用 wss:// 而非 ws://

HSTS 也會影響 WebSockets ,它會自動將非加密的 WebSocket 鏈接升級到 wss://

  • 對鏈接進行鑑權

    若是使用的是基於 Cookie 的鑑權機制,且 WebSocket 服務器與應用服務器在同一個域名下,那就能夠在 WebSocket 中繼續使用已有的會話。不過切記要對請求源進行驗證!

    若是不是基於 Cookie ,能夠在系統中建立一個單次使用、有時間限制並與用戶 IP 綁定的受權令牌,用該令牌對 WebSocket 進行受權。

  • 對鏈接源進行確認

    理解 WebSockets 的一個關鍵點在於要知道同源策略對其是無效的。任何一個能與你的系統創建 WebSocket 鏈接的網站,在使用 Cookie 鑑權的時候,都是能夠直接得到用戶信息的。所以,在 WebSocket 握手時,必需要確認鏈接源。能夠經過驗證請求頭中的 Origin 參數來確認。

若是想要作到雙重保險,能夠採用反跨站請求僞造令牌做爲 URL 參數。但針對每一個任務則須要建立一次性的獨立令牌,而不要直接使用反跨站請求僞造令牌,由於後者主要是用來爲應用的其它部分提供安全保障的。

2九、採用 U2F 令牌或客戶端證書,保護系統關鍵用戶免受釣魚攻擊

若是系統可能會面臨釣魚攻擊的威脅,說人話也就是,「若是存在這樣的可能性:攻擊者建立一個假的網站,騙取管理員/CEO 或其它用戶的信任,從而盜取其用戶名、密碼和驗證碼」,那麼就應該使用 U2F 令牌或客戶端證書來防止這種攻擊,這樣的話即便攻擊者有了用戶名、密碼和驗證碼也沒法得逞。

備註: 強調釣魚防禦對於通常用戶而言每每會帶來沒必要要的麻煩。然而,提供多一種可選項對終端用戶而言也非壞事。此外,向用戶提早告知釣魚攻擊的危險也是很是必要的。

30、針對跨站點泄露進行保護

跨站點泄露是一系列瀏覽器邊信道攻擊。這種攻擊使惡意網站能夠從其它 Web 應用程序的用戶中推測出信息。

這種攻擊存在已有時日,可是瀏覽器端倒是最近纔開始添加針對性的預防機制。能夠在 這篇文章 中瞭解關於該類攻擊的更多細節以及應該採起的安全控制措施。

2、服務器端的威脅防護

其次,是服務器端的威脅防護,這裏從應用系統、基礎設施、應用架構、應用監控、事件響應等不一樣側面,概括了以下建議:

2.1 應用系統

3一、對用戶輸入進行合法性驗證

該類別的措施中最關鍵的一點就是儘量嚴格地對全部用戶輸入進行合法性驗證。適當的驗證會使系統漏洞更難被發現和利用。對不合法的用戶輸入直接拒絕,而不要嘗試去清洗。驗證方面包括以下:

  • 採用嚴格的數據類型。針對日期採用 DataTime 類型,數字採用 Integer 類型等等。針對有固定可選項的狀況採用枚舉類型。儘可能避免採用字符串類型。
  • 若是必須採用字符串,至少給一個長度限制。
  • 若是必須採用字符串,將可輸入的字符集儘量地減小。
  • 若是要處理 JSON,使用 JSON 模式進行驗證。
  • 若是要處理 XML,使用 XML 模式進行驗證。

3二、異常處理優雅化,避免技術細節泄露

對終端用戶不要顯示堆棧記錄或相似的調試信息。採用全局的異常處理器對異常進行處理,展示給瀏覽器端簡單的錯誤信息。這樣會使攻擊者更難發現和利用系統中的漏洞。

3三、不要本身作鑑權

對用戶進行鑑權時可能會出現各類各樣的問題:要抵禦密碼猜測攻擊、用戶枚舉攻擊,要管理密碼重置、存儲用戶憑證,樣樣都不容易。就像密碼處理同樣複雜,咱們普通人仍是不要嘗試了。

直接使用 auth0 等相似的工具來進行身份驗證,採用一些普遍使用的、安全的軟件模塊來實現通訊協議(常見的爲 OpenID connect)。若是不想用 auth0 這類第三方的身份提供商,也能夠本身搭建一個相似 KeyCloak 的服務來代替。

3四、對一切都進行鑑權,減小攻擊面

應用系統要默認對一切都進行鑑權,除非是一些靜態資源、異常頁面或登出頁面。

3五、採用多重身份認證

萬一有人破解了身份認證服務呢?若是存在這種擔心,直接上多重身份認證(說人話也就是:除了密碼之外,還須要手機驗證碼)。這樣就算身份認證服務被黑、攻擊者能夠冒充到任何人,仍是沒法知道手機收到的驗證碼。

3六、經過嚴格的權限控制,避免對數據或功能的未受權訪問

權限控制雖不是件容易事,但也有妥善處理的方法:只要時刻記住不要在控制器方法中忘了對用戶權限進行驗證,從而帶來用戶越權的漏洞,包括:

  • 不要默認對全部控制器方法開通訪問權限。
  • 根據用戶角色劃分每一個控制器的訪問權限。
  • 採用方法級別的安全控制,限制對服務方法的訪問權限。
  • 採用集中化的權限管理工具,防止對每條記錄的非受權訪問。
  • 採用前端 Web 應用和後臺 API 結合的架構,對每一個 App 和 API 均採起權限控制,而不只是對與互聯網鏈接的部分進行控制。

爲了進一步澄清權限管理工具,這裏總結了一些要點:

  • 數據記錄要有能夠進行權限控制的字段,好比 int ownerId
  • 被受權的用戶要有一個 ID。
  • 要有一個類可用來進行權限評估,在數據記錄的 ownerId 與 用戶的 ID 相匹配時,能判斷出用戶具備對應的訪問權限。
  • 在以上基礎上,能夠將權限評估類集成到應用平臺的權限控制系統中,好比 Spring Security 產品的 PreAuthorize、PostAuthorize 等等。
  • 若是須要更復雜的權限控制,也能夠搭建一個完善的 ACL 系統。

3七、採用合適的工具和技術,避免注入漏洞

注入類的漏洞有不少,並且都很類似,包括 SQL 注入、HTML 注入、XML 注入、XPath 注入、命令注入、SMTP 注入、響應 header 注入等等。名稱不一樣但本質相同,相應地解決方法也相似:

  • 問題緣由: 使用字符串拼接,來構建特定協議下的參數化消息。
  • 解決方案:採用合適的、安全的、現成的工具來實現這項任務。

這裏不會深刻太多細節,只要記住:無論你是什麼協議,都謹記上面這點。後面會列舉一些常見的注入類漏洞。

3八、建立安全的數據庫查詢語句,避免 SQL 注入漏洞

若是要避免 SQL 注入漏洞,那就記住毫不要本身用字符串拼接 SQL 查詢語句。採用一個對象關係映射框架(ORM)來實現,可讓開發更高效、應用更安全。

若是想要構建更細粒度的查詢,能夠使用更底層一點的 ORM。

若是不能使用 ORM,那就嘗試預處理語句,但也要當心這類語句會比 ORM 更容易出現錯誤。

警告:

ORM 框架也不是萬能的,體如今兩方面:一是,它對原生的 SQL 查詢仍是支持的,最好不要使用這類查詢;二是,像其它任何軟件同樣,ORM 框架也會時不時被曝出漏洞。因此,仍是遵循咱們一而再再而三強調的策略:對全部輸入進行驗證,採用網絡應用程序防火牆(WAF),並保持軟件包的更新,這樣基本就能夠放心了。

3九、謹慎使用操做系統的命令行,防止命令注入的相關漏洞

若是能夠避免,最好不要執行操做系統命令。若是不能避免,那最好遵循如下準則:

  • 採用合適的庫/方法來構建命令及其參數。參數必須是 list 類型。不要用單獨字符串來建立命令。

  • 不用使用 shell 來調用命令。

  • 預約義好命令參數。好比 curl,若是容許用戶經過 -o 來指定參數,那麼攻擊者就有機會寫入到本地文件系統。

  • 瞭解程序如何執行,並相應地對參數進行驗證。再好比 curl,你可能只是想讓用戶能夠拉取某個網站的內容,但若是他拉取了 file:///etc/passwd,那就危險了。

  • 想清楚再行動。在上面的例子中,就算驗證了訪問地址是以 http:// 或 https:// 開頭,攻擊者也能夠發起以這兩類協議開頭的攻擊,如:http://192.168.0.1/internal_sensitive_service/admin。

  • 再強調一遍:真得要想清楚了再行動。就算你對 DNS 進行驗證,確保命令中不含敏感內網地址,你有去禁止將特定 DNS 記錄映射到 192.168.0.1 嗎?若是答案是否,那就危險了。

40、合理配置 XML 解析器,避免 XML 漏洞

做爲一種標記語言,XML 的危險性體如今它能夠訪問系統資源。XSLT 的一些實現甚至支持嵌入代碼。所以,在處理時必須很是謹慎。

  • 若是能夠,避免接受來自不受信任源的 XML/XSLT。

  • 若是要向 XML、XSLT 或 XPath 傳參,記住要使用安全的軟件組件,而不要使用字符串鏈接/格式化的方式。

  • 使用主流、安全的軟件組件來解析 XML/XSLT。不要使用錯誤的庫或代碼來處理 XML。此外,在任何狀況下,都不要試圖去徒手擼一個解析器(好比 SAML),很是容易出錯。

  • 正確配置解析器:禁用 XSLT 文檔、禁用 xinclude、禁用文檔類型定義、禁用外部實體,啓用 DOS 保護。具體配置在實現時會有所不一樣,但務必對所選擇的解析器進行深刻的研究。

4一、採用合適的類構建URL,避免 URL 注入漏洞

URL 注入常常會在如下狀況發生:

flavour = request.getParam("flavour");
url = "https:/api.local/pizzas/" + flavour + "/";
return get(url).json();
複製代碼

若是 flavour 被設置爲:

../admin/all-the-sensitive-things/
複製代碼

那麼這個 API 請求將會變爲 https://api.local/admin/all-the-sensitive-things/,是否是很兇險?

解決方案依然是採用合適的 URL 構建庫來爲 URL 傳參,從而能正確地對參數進行編碼。

4二、採用合適的類構建路徑,避免路徑遍歷漏洞

就像 URL 地址同樣,若是攻擊者設法在路徑中的某個地方偷偷地插入 ../../../ ,文件路徑可能最終指向意料以外的位置。要避免這種狀況,請建立一個類,採用這個類安全地構造路徑,並驗證最終路徑是否在預期目錄中。避免在文件路徑中使用不受信任的數據,或者更好的是,徹底避免使用文件系統,直接採用雲存儲。

4三、謹慎採用文件系統,接收不受信任的內容

若是容許用戶寫入服務器的文件系統,可能會出現各類各樣的問題。改用雲存儲,或者在數據庫中使用二進制 blob。

若是您必須訪問磁盤,則應遵循如下指導原則:

  • 不要讓不受信任的數據影響內部文件路徑。

  • 將文件保存在遠離 webroot 的隔離目錄中。

  • 在寫入磁盤以前,請驗證文件內容是否與預期格式匹配。

  • 正確設置文件系統權限以防止寫入不須要的位置。

  • 不要提取壓縮包(例如 ZIP),由於它們能夠包含任何文件,包括指向系統任意地方的連接和路徑。

4四、不要動態執行代碼,避免遠程代碼執行漏洞

不要使用 eval 或等效函數。找到一種其它的方法來實現代碼執行。不然,不受信任的數據將有可能進行函數調用,從而在有機會在服務器上執行惡意代碼。

4五、合理採用序列化,避免反序列化漏洞

對不受信任的數據進行反序列化是很危險的,很容易致使遠程代碼執行。

  • 若是能夠避免,不要使用序列化。

  • 若是能夠在服務器端序列化對象,則對其進行數字簽名。當須要再次反序列化它們時,請在繼續反序列化以前驗證簽名。

  • 使用一些主流的軟件組件,並保持更新。許多反序列化庫會一直被發現漏洞。GSon 是個不錯的選擇。

  • 使用簡單的文本格式,如 JSON,而不是二進制格式。此外,應該避免像XML這樣有問題的格式,由於這樣除了反序列化以外,還須要擔憂 XML 漏洞。

  • 在處理序列化對象以前驗證它。例如:對於 JSON,在繼續反序列化以前,根據嚴格的 JSON 模式驗證 JSON 文檔。

2.2 基礎設施

4六、採用網絡應用程序防火牆(WAF)

安裝防火牆,會減小不少風險。ModSecurity 就是一個很好的開源選擇。

4七、配置 Web 服務器,避免 HTTP desync 攻擊

HTTP desync,也稱 HTTP 請求走私攻擊,是指攻擊者劫持隨機用戶向系統發出的 HTTP 請求。這類攻擊通常在如下狀況下發生:

  • 前端服務器,好比負載均衡器或反向代理服務器,接受攜帶有 Content-length、Transfer-Encoding 等頭部參數的請求時,將請求未經處理隨即傳遞到後臺;

  • 後臺接受該請求的服務器(一般是應用服務器),採用(或被欺騙採用)一個不一樣於前端服務器的機制來肯定 HTTP 請求從何處開始、何處結束,好比前端服務器使用 Content-Length,而應用服務器採用 Transfer-Encoding;

  • 前端服務器重複利用與後端服務器的鏈接;

  • 前端服務器在與後臺服務器鏈接時採用 HTTP/1(而非 HTTP/2)。

那麼該如何進行防範呢?通常是根據所採用的產品:

  • 諮詢所採用的反向代理產品供應商,確保該產品具有主動防範攻擊的能力;

  • 配置前端服務器,在與後臺鏈接時採用 HTTP/2;

  • 配置前端服務器,防止利用同一個鏈接發送多個客戶端的 HTTP 請求;

  • 採用網絡應用程序防火牆(WAF),並確保其具有防止請求走私的模塊。

4八、採用容器

讓目標應用隔離其餘應用來運行。這樣,即便發生了攻擊事件,攻擊者也不會有權限去訪問未經許可的文件、系統或網絡資源。所以,最好使用 Kubernetes 或一個雲端環境來部署你的應用。若是由於某種緣由必須使用一臺服務器,那麼能夠手動採用 Docker 來約束應用。

4九、使用 SELinux/AppArmor

即便經過容器來運行應用,也仍是須要進一步採用 SELinux 或 AppArmor 策略來進一步地對應用作出約束,從而減小容器漏洞引起的威脅。

50、採用最少權限的服務帳戶

這種方法帶來的好處是即便發生了被攻擊事件,也能減小被攻擊形成的損失。再次重申,列出全部的情形是不可能的,這裏僅列舉一些例子幫助你們理解:

  • 即便使用了 Docker,甚至是使用了 SELinux/AppArmor,不要用 root 帳戶來運行你的應用。爲你的應用單首創建一個具有儘量少的權限的帳戶,從而下降攻擊者利用容器或內核漏洞等進行攻擊的可能性;
  • 若是有使用數據庫,確保應用程序中的數據庫用戶在訪問數據庫時具有儘量少的權限;
  • 若是應用中集成了 API,確保應用訪問 API 時具有儘量少的權限。

5一、限制外部網絡鏈接

攻擊者一般須要創建必定的反向通訊渠道來創建操控渠道或竊取數據。此外,一些漏洞也是須要外部網絡鏈接纔會被發現、被利用。

所以,不能讓應用隨便訪問外部網絡,包括 DNS。試下在服務器運行命令 nslookup www.example.com,若是運行成功,則說明你沒有對外部網絡鏈接作出適當的限制。如何處理此類問題,通常則取決於基礎設施。

針對外部的 TCP/UDP/ICMP 鏈接,通常能夠經過如下方式禁用:

  • 網關防火牆,若是有的話;
  • 若是是老式服務器,能夠採用本地的防火牆(例如 iptables 或 Windows 防火牆);
  • 若是服務器端採用 Docker,能夠使用 iptables;
  • 若是使用了 Kubernetes,可採用網絡策略定義。

DNS 處理起來稍微麻煩一點,咱們一般須要容許對一些 hosts 的訪問。

  • 若是有本地的 hosts 文件,那就很簡單,能夠採起上面的任何一種方式來將 DNS 完全禁用;
  • 若是沒有,那麼你須要在你上游的 DNS 中配置一個私有的區域,在網絡層限制僅能訪問該指定的 DNS 服務器。這個私有區域內只容許對一些預先指定的 hosts 的訪問。

5二、跟蹤 DNS 記錄,防止子域名劫持

子域名劫持發生場景舉例以下:

  1. 假如咱們擁有一個域名 example.com;

  2. 針對一次促銷活動,咱們買了另外一個域名 www.my-cool-campaign.com ,而後建立了一個別名從 campaign.example.com 映射到 www.my-cool-campaign.com;

  3. 此次促銷活動結束後,www.my-cool-campaign.com 域名也到期了;

  4. 可是,從 campaign.example.com 到 www.my-cool-campaign.com 的別名映射仍存在;

  5. 若是有人購買了這個到期的域名,那麼 campaign.example.com 即可以直接指向該域名;

  6. 若是攻擊者在 www.my-cool-campaign.com 域名下提供一些惡意內容,那麼即可以經過 campaign.example.com 域名直接訪問到;

所以,須要隨時留意你的 DNS 記錄。若是須要處理的相似狀況較多,強烈建議你作一個自動監控方案。

2.3 架構

5三、建立內部 API 用來訪問數據源

對鏈接互聯網的網絡應用程序不該該太過於信任。例如,不該容許它進行數據庫直連。不然,當有人攻破應用程序時,整個數據庫都將面臨威脅。

相反,咱們應該搭建多組件組成的架構,例如:

  • 咱們域名爲 www.example.com 的應用程序使用 auth0 進行鑑權。

  • 該應用程序訪問內部 API 服務 api.example.local 時,攜帶被受權用戶的 token,放在請求頭部的 Authorization 中。

  • 位於 api.example.local 的 API 服務根據用戶的 token 進行訪問限制,進而根據被授予的權限讀寫數據庫。

假如如今有黑客想要攻破咱們的應用程序,即便成功,他也沒有權限訪問整個數據庫,而只是利用某個用戶的 token,進而訪問該 token 所容許訪問的那部分數據。

5四、內部鏈接也需加密和驗證

不要盲目相信內網的安全性,有不少方法能夠攻破它。對於系統間的訪問,所有采用 TLS(也就是 HTTPS)進行加密,最好在網絡和系統兩個層次對鏈接進行鑑權。

5五、對敏感信息集中管理

若是沒有采用合適的敏感信息管理方案,就很難保持受權的短時間性化、可審計性和祕密性。所以,建議採用 HashiCorp Vault 一類的工具來集中管理密碼、加密 key 等相似信息。

2.4 監控

5六、收集,分析,報警

集中收集日誌到一個獨立系統,好比 SIEM(安全信息和事件監控系統)。在這個系統中,能夠在一些表徵脆弱性、攻擊的事件發生時進行報警。當嚴重威脅發生時,能夠當即通知相關人員。

5七、收集系統安全事件

最重要的日誌來源可能就是系統自身了。當有可疑行爲發生時,系統應能引起異常,記錄事件,可能的話,甚至能夠自動封鎖可能帶來問題的用戶或IP地址。常見可疑行爲包括:

  • 輸入值的合法性驗證錯誤(例如,試圖輸入 UI 中不可能提供的值)
  • 訪問控制錯誤 (例如,嘗試訪問一條在 UI 中不可能出現的記錄)
  • 數據庫語法錯誤表示某我的發現了一處 SQL 注入的脆弱性,這時候可要動做快點採起行動了
  • XML 錯誤表示某我的發現了一處 XML 注入的脆弱性,或者正嘗試利用 XXE(XML 外部實體)脆弱性進行攻擊
  • 錯誤請求表示用戶可能發送了被應用拒絕的請求。Spring 框架的 RequstRejectedException 就是一個例子
  • 反跨站請求僞造令牌驗證錯誤通常表示有人正嘗試尋找系統中存在的脆弱性

5八、收集運行時安全日誌

使用運行時安全監控工具如 Falco 來對異常系統訪問進行檢測。若是採用了 Kubernetes,那麼 Falco 就特別有用。遠程也能夠對日誌進行收集和監控。

5九、收集 SELinux/AppArmor 日誌

假如咱們制定了 SELinux 策略防止向外部的鏈接,但系統突然向外部某個網站(例如 burpcollaborator.net)發起 HTTP 請求,那就須要馬上引發關注。又或者你的系統嘗試訪問 /etc/passwd。這兩種狀況都表示有人已經發現了咱們系統中的漏洞。

60、收集 Web 服務器事件

對 Web 服務器軟件,至少要對訪問日誌和錯誤日誌進行收集,收集後發送到集中式的日誌服務器。在突發事件響應時,這將輔助咱們快速理清時間線。

6一、收集網絡應用程序防火牆(WAF)日誌

若是你像上文推薦使用了網絡應用程序防火牆(WAF),那麼也對這個日誌進行收集。但不用針對這個日誌設置報警,由於它基本上會收到來自互聯網各類各樣的問題,並且不部分是你不用擔憂的。

2.5 事件響應

6二、制定應對計劃

一旦對咱們的系統進行了監控和加固,攻擊者將難以快速定位系統漏洞,即便最終發現,咱們也能快速瞭解狀況。

但僅瞭解狀況是不夠的,還須要作出以下準備:

  • 快速分析系統日誌,瞭解當前情況和需採起的對應措施
  • 在應用防火牆等產品中,快速對個別 url 地址和參數作出限制
  • 若有須要,快速關停系統

6、開發管理

6三、威脅模型

系統地考慮一下「可能會出現哪些問題」並據此作出調整。設計一個新的系統時,越早開始這一步越好。當對系統發生改變時,再從新梳理一遍這個過程。

例如:

小王:若是攻擊者攻破了咱們鏈接了互聯網的服務器,怎麼辦?

小陳:那可就完蛋了!

小王:好吧!這就說明咱們在這裏存在着一個信任關係,咱們認爲鏈接了互聯網的服務器是不會被攻破的。咱們能夠信任這一點嗎?

小陳:未必吧!有一百種可能致使咱們的服務器被黑掉,例如咱們代碼中存在的脆弱性,或者依賴中存在的脆弱性,或者是咱們 Web 服務器所安裝軟件的脆弱性。

小王:好吧!那就讓咱們打破這層信任關係。接下來該作些什麼呢?

小陳:咱們這樣來分解一下系統:建立一些內部的接口用來實際訪問數據庫,由此以來,前端的 Web 服務器就不能直接訪問後臺的全部東西。

小王:這是個好辦法!除此之外,還有其它什麼可能出問題呢?

小陳:嗯,若是黑客攻破了咱們的內網呢?

小王:那全部東西都要丟失了,由於內網裏服務器之間的鏈接都是未加密的。

小陳:……

這就是威脅模型,它不須要多麼複雜。使用這種方式,來找出系統中可能存在的威脅。

6四、源代碼強制審查

經過技術控制手段,防止代碼未經他人審覈便提交入庫。這是構建安全開發環境的基礎,由於它能夠作到:

  1. 若是攻擊者攻陷了一個開發人員的電腦,或者是開發人員自身企圖發起攻擊,將不能直接將惡意代碼遷入代碼庫;

  2. 若是開發人員的錯誤致使引入了有漏洞的代碼,極可能在被其餘人檢查時及時發現。

6五、自動化持續集成管道,僅容許簡單訪問

開發人員應該有權限觸發 Jenkins 構建,且 Jenkins 權限配置也僅該如此,不要再容許其它權限。單個開發人員應該不能在構建階段引入任意代碼。固然,若是像上文推薦的強制性地採用了代碼審查,Jenkinsfile 也能夠保存在版本管理工具中。

6六、對 artifacts 進行簽名

若是是構建容器鏡像,能夠把對鏡像簽名做爲構建的一步。將簽名密鑰存儲在安全的地方。構建階段須要訪問密鑰,可是杜絕將密鑰與 Jenkinsfile 一塊兒存儲在版本管理工具中。更好的方式是將密鑰存儲在 HashiCorp Vault 之類的地方,而後在構建時再進行拉取。

6七、持續集成管道中加入靜態應用程序掃描器

在持續集成管道中使用 SpotBugsFind-Sec-Bugs(或者根據你所採用的技術棧進行選擇)之類的工具。它們能夠幫你在部署代碼以前發現已知的漏洞。

此外,也能夠做爲 IDE 的插件安裝在開發人員的電腦上,在代碼遷入以前就運行這些工具進行檢查。

6八、構建時對依賴進行檢查,保證最小的依賴集

應用程序中依賴的每一個軟件包都是一個風險來源。經過依賴,咱們拉取了第三人的代碼並在咱們的應用服務器上執行,因此,必需要搞清楚咱們依賴的這個軟件包是什麼,爲何會依賴它?

  1. 保持最小的依賴集;

  2. 僅使用咱們所信任的依賴。它們必須是普遍使用和廣爲人知的;

  3. 採用構建框架,對依賴進行確認。

此外,嚴格控制應用服務器的對外鏈接,從而避免後門的存在。

6九、對依賴進行安全掃描

使用 OWASP 依賴檢查工具對依賴中常見的安全問題進行掃描。除了在持續集成管道中,也能夠在開發人員的開發環境運行這些工具。

70、持續集成管道對鏡像進行安全掃描

若是採用了容器化技術,能夠使用 Trivy 等工具對容器鏡像進行一些常規漏洞的掃描。

7一、自動化部署和簽名驗證

開發人員能夠有權限到生產環境中部署,可是權限範圍應該控制在前階段已經構建和簽名過的特定鏡像,而不是直接訪問生產服務器。若是是使用 Kubernetes,能夠經過 Notary 或開放策略代理來驗證待部署鏡像的簽名。

7二、設置一個安全人員

一我的的精力是有限的。咱們不能指望每一個開發人員都精通滲透測試或是安全工程師。正如你不能指望全部的安全專家都是優秀的開發人員同樣。所以,能夠在團隊中設置一個專門關注安全的人員,主要與開發人員、架構師進行交流,幫助保護咱們的應用程序並在團隊中傳播安全意識。

3、結論

保證應用程序的安全性,光靠避免漏洞時不夠的,必須全面通盤考慮,主動進行防護。這裏對一些主要方法進行了總結:

  • 使用最新版本的的軟件組件來執行危險的操做,如身份驗證、訪問控制、加密、訪問數據庫或解析 XML,並確保正確配置了這些組件,例如 XML 解析時禁用外部實體。

  • 使用平臺提供的安全控制,例如反跨站請求僞造保護。

  • 使用 Web 瀏覽器提供的安全控件,如 HSTS、SameSite Cookie 和內容安全策略。

  • 對安全控制進行集中化處理,特別是身份驗證和訪問控制,從而避免一些遺漏,如在某些控制器方法上忘記對安全進行控制。

  • 使用 Web 應用程序防火牆,防止應用程序漏洞被發現和被利用。

  • 經過限制對文件、網絡和系統資源的訪問來對應用程序進行限制。

  • 利用威脅模型發現架構中的威脅,並相應進行處理。既包括在源代碼層面對每一個開發人員的源代碼進行安全控制,也包括在架構層面對前端 Web 服務器的安全控制。

  • 對系統進行監控,制定異常處理預案。

  • 在開發環境和持續集成環境中使用漏洞掃描程序對代碼、鏡像、依賴進行掃描。

  • 對開發人員、架構師等開展安全培訓,並在團隊中配備一名安全人員。


若是你看到最後必定是收穫頗豐,這裏還有一個收穫更多知識的方法,但比讀完這篇文章要可貴多,加入咱們一塊兒變強!

變強之路充滿荊棘,因此強者才受人尊敬

相關文章
相關標籤/搜索