OWASP 關於會話管理 - 譯文 [原創]


英文原文:https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Session_Management_Cheat_Sheet.md
采集日期:2019-07-17
注:本文 Session 與 “會話” 通用。

簡介(Introduction)

Web 身份認證、Session 管理和訪問控制:(Web Authentication, Session Management, and Access Control)

所謂 Web 會話(Session),就是與同一用戶相關聯的一連串網絡 HTTP 請求和響應。當今較為復雜的 Web 應用程序,都需要在多次請求期間為每個用戶維持信息或狀態數據。為此,Session 提供了建立變量的能力 - 比如訪問權限和本地化設置 - 用戶在 Session 存續期內每次與 Web 應用程序的交互都能使用這些變量。

在首次用戶請求之后,Web 應用程序即可創建 Session 對匿名用戶進行追蹤記錄。比如可以記錄用戶的語言首選項。此外,只要用戶完成了身份認證(Authentication),Web 應用程序就要用到 Session 了。這樣在后續所有請求中,就確保能識別出用戶,也能進行安全訪問控制,也能對用戶私有數據進行授權訪問,以及增加應用程序的適用性。因此,在身份驗證之前和之后,當今的 Web 應用程序都能提供 Session 的支持能力。

已通過身份認證的 Session 一經建立,Session ID(或 Token)就臨時等同於應用程序最堅固的身份認證方法,正如用戶名和密碼、密碼短語(Passphrase)、一次性密碼(OTP)、基於客戶端的數字證書、智能卡或生物識別技術(比如指紋或視網膜)。 參見 OWASP 的 Authentication Cheat Sheet

HTTP 是一種無狀態協議(RFC2616第5節),其每一對請求和響應均與其他 Web 交互過程相互獨立。因此,為了引入 Session 的概念,需要實現 Session 的管理功能,該功能將 Web 應用程序中常用的身份認證和訪問控制(或授權 Authorization)模塊關聯起來:

Session 示意圖

Session ID 或 Token 將用戶身份認證憑據(以用戶 Session 的形式)綁定到用戶的 HTTP 傳輸過程和 Web 應用程序執行的訪問控制。當今 Web 應用程序中的這3個組件(身份認證、Session 管理和訪問控制)相當復雜,而且事實上其實現和綁定過程都得靠 Web 開發人員自己來完成(因為 Web 開發框架並未對這些模塊之間的嚴格關聯提供支持),這就讓實現安全的 Session 管理模塊變得極具挑戰性。

Session ID 的泄露、捕獲、預測、暴力破解或固定(Fixation),都將導致 Session 劫持(Hijack 或 Sidejack)攻擊,這時攻擊者能夠完全模擬 Web 應用程序中的受害用戶。攻擊者可以執行兩類 Session 劫持攻擊,目標攻擊或泛攻擊。在目標攻擊中,攻擊者的目標是假冒特定(或擁有特權)的 Web 應用程序受害用戶。而在泛攻擊時,攻擊者的目標是假冒(或獲取訪問權限)Web 應用程序中的任何有效或合法用戶。

Session ID 的特性(Properties)

為了維持用戶認證狀態,並記錄用戶在 Web 應用程序中的位置,應用程序會向用戶提供一個在創建 Session 時分配的 Session 標識符(Session ID 或 Token)。在 Session 存續期間,用戶和 Web 應用程序將共同持有並相互交換(Exchange)此標識符(每次 HTTP 請求都會發送)。Session ID 是一個鍵值對(name = value pair)。

為了實現安全的 Session ID,標識符(ID 或 Token)的生成必須滿足以下特性。

Session ID 名稱的識別(Fingerprint)

Session ID 使用的名稱不應過於描述性,也不應給出與 ID 的用途和含義相關的無謂細節。

對於那些最常見的 Web 應用程序開發框架,其采用的 Session ID 名稱很容易識別出來,比如 PHPSESSID (PHP), JSESSIONID (J2EE), CFID & CFTOKEN (ColdFusion), ASP.NET_SessionId(ASP .NET)等。因此,Session ID 的名稱可以揭示出 Web 應用程序采用的技術和編程語言。

建議將 Web 開發框架默認的 Session ID 名稱更改為id之類的通用名。

Session ID 的長度

攻擊者可能會遍歷 Session ID 的整個取值范圍,並驗證是否存在合法的 Session 。為了防范這種暴力攻擊,Session ID 必須擁有足夠的長度。

Session ID 的長度必須至少為128位(16字節)

注意

  • 根據下一節Session ID 的熵值中給出的假設,這里給出128位的 Session ID 長度以供參考。但該長度不應被視為絕對不變的最小值,因為實現過程中的其他因素可能會影響其強度。
  • 例如,有些知名的實現方案是這樣的,正如 Microsoft ASP.NET session ID 所述:“*ASP.NET 的 Session 標識符是一個隨機生成的數字,並編碼為24個字符長度的字符串,由 a 到 z 的小寫字母和 0 到 5 的數字組成”。
  • 這個長度能夠提供很好的有效熵,因此可被視為足以躲避猜測或暴力攻擊。

Session ID 的熵值(Entropy)

為了防范上述猜測攻擊,Session ID 必須是不可預測的(足夠隨機)。在猜測攻擊時,攻擊者能夠通過統計分析技術,猜測或預測合法 Session 的 ID。因此,必須采用優質的 PRNG(偽隨機數生成器,Pseudo Random Number Generator)。

Session ID 值必須至少能支持64位的熵值。如果采用了優質的 PRNG,則該熵值差不多是 Session ID 長度的一半。

注意

  • 其實,Session ID 的熵值會受到其他外部因素和難以評估因素的影響,比如 Web 應用程序日常並發活動 Session 數、Session 絕對過期時間(Absolute session expiration timeout)、攻擊者每秒可生成猜測的及目標 Web 應用程序可支持的 Session ID 數量等。

  • 如果采用熵值為64位的 Session ID,則1個攻擊者至少要耗費292年才能成功猜出1個合法的 Session ID。這里假設攻擊者每秒可以嘗試10,000次猜測,並且 Web 應用程序中同時有100,000個 Session 可用。

  • 更多信息請看這里

Session ID 的內容(或值)

為了防止信息泄露攻擊,Session ID 的內容(或值)必須沒有什么含義。在信息泄露攻擊時,攻擊者能夠解碼 ID 的內容,並提取出用戶、 Session 或 Web 應用程序內部工作過程的細節。

Session ID 必須只是客戶端的標識符而已,其值絕不能包含敏感信息(或 PII)。

與 Session ID 關聯的含義、業務或應用程序邏輯,都必須保存在服務器端,具體來說就是存儲在 Session 對象、 Session 管理數據庫(Database 或 Repository)中。

這里保存的信息可以包括:客戶端 IP 地址、User-Agent 信息、電子郵件、用戶名、用戶 ID、角色、權限級別、訪問權限、語言首選項、賬戶 ID、當前狀態、上次登錄信息、 Session 超時時間和其他內部 Session 詳細數據。如果 Session 對象及屬性包含了敏感信息(如信用卡號碼),則需要對 Session 管理存儲庫進行適當的加密和保護。

建議采用 SHA256 之類的加密哈希函數來創建密碼強度較高的 Session ID。

Session 管理功能的實現(Session Management Implementations)

Session 管理功能定義了用戶和 Web 應用程序之間將會采用的交換機制,以便共同持有並持續交換 Session ID。在 HTTP 協議中有多種機制可用於維護 Web 應用程序的 Session 狀態,例如 cookie(標准 HTTP 頭)、URL參數(URL重寫 - RFC2396)、基於 GET 請求的 URL 參數、基於 POST 請求的 body 參數(比如隱藏的 HTML 表單字段)或專門的 HTTP 頭。

建議 Session ID 交換機制應該允許定義高級的 Token 屬性,例如 Token 過期日期和時間、粒度約束。Cookie(210929656265)能成為應用最廣的 Session ID 交換機制之一,原因之一就是 Cookie 能提供其他方法所不具備的高級功能。

某些特定 Session ID 交換機制的采用,比如在 URL 中包含 ID,可能會泄露 Session ID(在 Web 鏈接和日志、Web 瀏覽器歷史記錄和書簽、Referer 頭部信息或搜索引擎中),並且還會為其他類型的攻擊提供便利,如操縱 ID 或會話固定攻擊(Session Fixation Attack)

內置 Session 管理功能的實現(Built-in Session Management Implementations)

Web 開發框架(如J2EE,ASP .NET,PHP等)提供了自己的 Session 管理功能和相關的實現方案。推薦采用這些內置框架,而不是從頭開始構建自制的框架,因為這些內置框架已在全球范圍內應用於多種 Web 環境,並且已經過 Web 應用程序安全和開發社區的測試。

不過,請注意這些框架曾經也存在過漏洞和弱點,因此始終建議大家采用最新的可用版本,新版系統有可能會修復所有知名漏洞,並按照本文所述的建議檢查及修改默認配置,以便增強其安全性。

Session 管理機制用於暫存 Session ID 的存儲或數據庫必須安全可靠,以保護 Session ID 免遭本地或遠程的意外泄露及未經授權的訪問。

已在用和已采納的 Session ID 交換機制(Used vs. Accepted Session ID Exchange Mechanisms)

Web 應用程序應該利用 Cookie 進行 Session ID 交換管理。如果用戶通過其他交換機制(例如 URL 參數)提交 Session ID,則 Web 應用程序應該不予接受,這算是阻止會話固定攻擊的防御策略之一。

注意

  • 即便是采用 Cookie 作為默認的 Session ID 交換機制,Web 應用程序仍然可能能夠接受別的交換機制。
  • 因此,在處理和管理 Session ID 時,需要通過全面測試來確認 Web 應用程序當前可接受的所有交換機制,並將可接受的 Session ID 記錄機制限制為僅支持 Cookie。
  • 以前有一些 Web 應用程序曾經采用 URL 參數作為交換機制,或者在滿足某些條件時甚至可從 Cookie 切換成 URL 參數(通過 URL 自動重寫技術),這些條件諸如 Web 客戶端確認不支持 Cookie,或者因考慮用戶隱私而不接受 Cookie。

傳輸層的安全性(Transport Layer Security)

為了保護 Session ID 交換過程在網絡傳輸時免遭主動竊聽(Active Eavesdrop)和被動泄露,必須強制對整個 Web 會話采用加密 HTTPS(SSL/TLS)連接,而不僅只是對交換用戶憑據時的身份認證過程才使用 HTTPS。

此外還必須采用 Cookie 的 Secure 屬性來確保僅通過加密通道交換 Session ID。使用加密通信通道還能保護 Session 免受某些會話固定攻擊,這時的攻擊者能夠攔截並操縱網絡傳輸過程,以便在受害者的 Web 瀏覽器上注入(或修正)Session ID,參見此處此處

以下是一些有關 HTTPS(SSL/TLS)的最佳實踐,重點關注對 Session ID 的保護(特別是在使用 Cookie 時),以及在 Web 應用程序中集成 HTTPS:

  • Web 應用程序絕不能把已存在的 Session 從 HTTP 切換到 HTTPS,反之亦然,因為這將在網絡上以明文形式泄露 Session ID。

  • Web 應用程序不應在同一主機(甚至是域,請參閱 Cookie 的 Domain 屬性)上混合使用加密和未加密的內容(HTML 頁面、圖像、CSS、Javascript 文件等),因為未加密通道上對任何 Web 對象的請求都有可能泄露 Session ID。

  • 通常 Web 應用程序不應由同一主機同時提供公開的未加密內容和私密的加密內容。建議改為使用兩台不同的主機,比如公開內容通過 HTTP(未加密)的 www.example.com,而私密和敏感內容(存在 Session)則通過 HTTPS(加密)的 secure.example.com。前者只開放 TCP/80 端口,而后者只開放 TCP/443 端口。

  • Web 應用程序應該避免主頁從 HTTP 到 HTTPS 的重定向跳轉(用 30x HTTP 響應),這種重定向是相當常見的做法。因為這一個未受保護的 HTTP 請求/響應交換過程會被攻擊者用於收集(或修正)合法的 Session ID。

  • Web 應用程序應該利用 HTTP Strict Transport Security (HSTS)(曾被稱作 STS)以強制使用 HTTPS 連接。

參見 OWASP Transport Layer Protection Cheat Sheet

有一個重點需要強調一下,SSL/TLS(HTTPS)無法防范 Session ID 預測、暴力破解、客戶端篡改或 Session 固定攻擊。不過到目前為止,從網絡傳輸過程中泄露和捕獲 Session ID,仍然是最普遍的攻擊途徑(Vector)之一。

Cookie

基於 Cookie 的 Session ID 交換機制提供了多種安全特性,可用於保護 Session ID 的交換過程。這些特性以 Cookie 屬性的形式提供:

Secure 屬性

Cookie 的 Secure 屬性通知 Web 瀏覽器只能通過加密的 HTTPS(SSL/TLS)連接發送 Cookie。該會話保護機制可以確保防止 Session ID 經由 MitM(中間人)攻擊而泄露 。它確保攻擊者無法從 Web 瀏覽器傳輸過程中輕易捕獲 Session ID。

即便強制 Web 應用程序僅采用 HTTPS 協議進行通信,甚至 Web 應用程序所在主機關閉了 HTTP 的 TCP/80 端口,但如果未設置 Cookie 的 Secure 屬性,那么仍然無法防止 Session ID 的泄露。因為 Web 瀏覽器仍可以被蒙在鼓里,通過不加密的 HTTP 連接泄露出 Session ID。攻擊者可以攔截和操縱受害用戶的網絡傳輸過程,並向 Web 應用程序注入未加密的 HTTP 引用,此引用將強制 Web 瀏覽器以明文形式提交 Session ID。

參見 Secure 標志

HttpOnly 屬性

Cookie 的 HttpOnly 屬性通知 Web 瀏覽器不允許腳本(比如 JavaScript 或 VBscript)通過 DOM document.cookie 對象訪問 Cookie。該條 Session ID 保護措施可以確保無法通過 XSS 攻擊竊取 Session ID。

參見 OWASP XSS (Cross Site Scripting) Prevention Cheat Sheet

參見 HttpOnly

SameSite 屬性

服務器可以定義 Cookie 的 SameSite 屬性,使得瀏覽器無法對跨站(Cross-site)請求發送該 Cookie。其主要目標是降低跨域(Cross-origin)信息泄露的風險,並為抵御跨站請求偽造攻擊提供一些保護。

參見 SameSite

Domain 和 Path 屬性

Cookie 的 Domain 屬性 通知 Web 瀏覽器,只向指定的域及其全部子域發送該 Cookie。如果未設置 Domain 屬性,則該 Cookie 默認只會發送給源服務器。Cookie 的 Path 屬性通知 Web 瀏覽器,只向 Web 應用程序內的指定目錄或子目錄(或路徑、資源)發送該 Cookie。如果未設置 Path 屬性,則默認只會為被請求且設置了該 Cookie 的資源所在目錄(或路徑)發送該 Cookie。

建議縮小或限制這兩個屬性的使用范圍。這樣,就不應設置 Domain 屬性(將Cookie 限定於源服務器),並且應將 Path 屬性盡可能限定為需要用到 Session ID 的 Web 應用程序路徑。

如果 Domain 屬性設置得過於寬松,比如 example.com,攻擊者就能用此 Session ID 對同一域中的其他主機和 Web 應用程序發起攻擊,這被稱為跨子域 Cookie。例如,www.example.com 中的漏洞或許能讓攻擊者從secure.example.com 中獲取到 Session ID。

此外,建議不要在同一域中混合部署不同安全級別的 Web 應用程序。某一個 Web 應用程序中的漏洞,或許能讓攻擊者利用寬松的 Domain屬性(如 example.com),為同一域內的其他 Web 應用程序設置 Session ID,這是一種在會話固定攻擊時可被采用的技術。

盡管 Path 屬性允許用同一主機上的不同路徑隔離不同 Web 應用程序的 Session ID,但仍然強烈建議不要在同一主機上運行不同的 Web 應用程序(尤其是不同的安全級別或范圍)。這些應用程序可以用其他方法來訪問 Session ID,比如 document.cookie 對象。並且任何 Web 應用程序都可以為該主機中的任何路徑設置 Cookie。

Cookie 很容易受到 DNS 欺騙/劫持/中毒攻擊,這時攻擊者可以操縱 DNS 解析系統來強制 Web 瀏覽器公開給定主機或域的 Session ID。

Expire 和 Max-Age 屬性

基於 Cookie 的 Session 管理機制可以采用兩種類型的 Cookie:非持久性(或 Session)Cookie 和持久性 Cookie。如果 Cookie 給出了 Max-Age(優先於 Expires)或 Expires 屬性,則其會被視作一個持久性 Cookie,並將由 Web 瀏覽器存入磁盤至過期為止。

通常,如果在身份認證通過后, Session 管理功能需要記錄用戶狀態信息,則可利用非持久性 Cookie。在當前 Web 瀏覽器實例關閉后,這會強制讓 Session 從客戶端消失。因此,如果想要進行 Session 管理,則強烈建議采用非持久性 Cookie,使得 Session ID 不會在 Web 客戶端緩存中長期留存,而攻擊者正是從緩存中獲取到它的。

  • 確保使用敏感信息時應按需進行非持久化/加密/存儲,以確保 Cookie 中不包含敏感信息。
  • 確保無法經由 Cookie 操作進行未經授權的活動。
  • 確保已設置了 Secure 標志,以防止經由網絡用非安全方式進行意外傳輸。
  • 確定應用程序代碼中的所有狀態轉換是否都對 Cookie 做了正確檢查並強制啟用。
  • 如果 Cookie 中存有敏感數據,請確保對整個 Cookie 進行加密。
  • 應用程序用到的所有 Cookie 都有明確的定義,具備名稱和使用理由。

HTML5 Web 存儲 API

Web 超文本應用技術工作組(WHATWG,Web Hypertext Application Technology Working Group)給出了 HTML5 Web 存儲 API 的說明,包括 localStoragesessionStorage,以此作為客戶端存儲鍵值對(Name-value)的機制。

與 HTTP Cookie 不同,localStoragesessionStorage 中的內容在瀏覽器的請求或響應中不會自動分享,而是用於在客戶端存儲數據。

localStorage API

作用域(Scope)

所有由同一服務源加載的頁面,都可以訪問用 localStorage API 存儲的數據。該服務源以 Scheme(https:\\)、主機(example.com)、端口(443) 和域(domain/realm)(example.com)的形式定義。

這種數據訪問方式與帶 Secure 標志的 Cookie 類似,意味着無法通過 http 協議讀取經由 https 協議存儲的數據。由於各自獨立的窗口/線程存在並發訪問的可能,所以用 localStorage 存儲的數據可能較易遭遇共享訪問問題(如競態條件 Race-condition),其應被視作無鎖形態的(Non-locking)(Web 存儲 API 規范)。

存活時間(Duration)

localStorage API 存儲的數據在整個瀏覽 Session 中保持存活,從而延長了可供其他系統用戶訪問的期限(Timeframe)。

脫機訪問(Offline Access)

標准中不要求對 localStorage 數據作靜態加密(Encrypted-at-rest),這意味着有可能從磁盤直接訪問到這些數據。

適用場景(Use Case)

WHATWG 建議,localStorage 可用於需要跨多個窗口或 Tab 頁、跨多個 Session 訪問的數據,以及為了性能可能需要存儲大量(幾兆字節)數據的場合。

sessionStorage API

作用域(Scope)

sessionStorage API 在調用它的窗口上下文中存儲數據,這意味着 Tab 1 無法訪問由 Tab 2 存儲的數據。

並且,與 localStorage API 類似,所有同一服務源加載的頁面都可以訪問 由 sessionStorage API 存儲的數據,該服務源以 Scheme(https:\\)、主機(example.com )、端口(443)和域(domain/realm)(example.com)的形式定義。

這種數據訪問方式與帶 Secure 標志的 Cookie 類似,意味着無法通過 http 協議讀取經由 https 協議存儲的數據。

存續時間(Duration)

sessionStorage API 僅存儲當前瀏覽 Session 存續期間的數據。只要 Tab 頁一經關閉,數據就不再可讀。如果瀏覽器 Tab 頁被重新啟用或保持打開狀態,則數據不一定會被阻止訪問。數據還有可能留存於內存之中,直至發生一次垃圾回收事件為止。

脫機訪問(Offline Access)

標准中不要求對 sessionStorage 數據作靜態加密,這意味着有可能從磁盤直接訪問到這些數據。

適用場景(Use Case)

WHATWG 建議:sessionStorage 可用於與業務流程(Workflow)的某個實例相關的數據,如一次訂票記錄的詳細信息,只是可能在其他 Tab 頁同時執行着多個業務流程。這種與窗口/Tab 頁綁定的特性,使得數據不會在各個 Tab 頁的業務流程之間相互泄漏。

安全風險(Security Risk)

通常,保密或敏感數據不應持久存儲在瀏覽器的數據存儲中,因為在共用系統中這可能會造成信息泄漏。由於 Web 存儲機制只是一些 API,所以注入腳本也有可能訪問得到,這使得它的安全性要低於采用了 HttpOnly 標志的 Cookie。

雖然 sessionStorage 有一種用途就是存儲業務流程相關的某些數據,以供某 Tab 頁/窗口在多次重新加載(Reload)之間仍能使用,但仍應該將 Web 存儲 API 當作不安全的存儲來看待。因此,假如業務解決方案需要采用 localStoragesessionStorage 來存儲敏感數據,則應該對數據進行加密並實施重現攻擊防護(Replay Protection
)。

由於通過 XSS 攻擊有可能訪問到 Web 存儲 API,所以應該用非持久性 Cookie 來保存 Session ID,並應用適當的標志來防止不安全的訪問Secure), XSSHttpOnly)和CSRF問題(SameSite)。

參考文獻(Reference)

Session ID 的生命周期(Life Cycle)

Session ID 的創建和校驗:寬松和嚴格的 Session 管理(Session ID Generation and Verification: Permissive and Strict Session Management)

Web 應用程序有兩種類型的 Session 管理機制,即寬松型和嚴格型,這與會話固定漏洞相關。寬松型機制允許 Web 應用程序最初接受用戶設置的任意 Session ID 值作為合法值,並為其創建新的 Session 。而嚴格型機制則要求 Web 應用程序僅接受先前由該應用程序生成的 Session ID 值。

會話 Token 應盡可能交由 Web 服務器進行處理,或由經加密保證安全的隨機數生成器生成。

目前最常用的機制是嚴格型機制(更安全,PHP 默認采用寬松型)。開發人員必須確保 Web 應用程序不會在某些場合下采用寬松型機制。Web 應用程序絕對不允許接受未經它們生成的 Session ID。如果收到陌生的 ID,就應該生成並向用戶提供新的合法 Session ID。此外,這種非法場景應該被檢測為可疑活動,並應生成警告。

將 Session ID 視同其他用戶輸入數據一樣管理(Manage Session ID as Any Other User Input)

與 Web 應用程序需要處理的任何其他用戶輸入數據一樣,Session ID 必須被視為不受信任數據,並且必須對其進行完整的驗證(Validate)和校驗(Verify)。根據所用的 Session 管理機制不同,Session ID 將接收於 GET 或 POST 參數、URL 或 HTTP 頭(如 Cookie)之中。如果 Web 應用程序在進行處理之前未驗證並濾除非法的 Session ID,則它們可能會用於發掘出其他 Web 漏洞。例如,如果 Session ID 存儲在關系數據庫中,則可能是 SQL 注入;如果 Session ID 由 Web 應用程序存儲並返回,則可能是持久性 XSS 。

權限發生任何變化之后都得更新 Session ID(Renew the Session ID After Any Privilege Level Change)

在用戶 Session 相關的權限級別發生任何變化后,Web 應用程序都必須更新(Renew)或重新生成 Session ID。最常見的必須重新生成 Session ID 的場景,就是在身份認證的過程中,因為用戶的權限級別由未經認證(或匿名)狀態更改為通過認證狀態了。其他的常見場景也必須考慮在內,諸如修改密碼、更改權限或由 Web 應用程序的普通用戶角色切換為管理員角色。Web 應用程序中的所有這些關鍵頁面,都必須略除先前的 Session ID,必須為新接收到的每個針對關鍵資源的請求分配新的 Session ID,並且先前的舊 Session ID 必須被銷毀。

最常見的 Web 開發框架都提供了更新 Session ID 的函數和方法,諸如 request.getSession(true)HttpSession.invalidate()(J2EE)、Session.Abandon()Response.Cookies.Add(new...)(ASP .NET)、session_start()session_regenerate_id(true)(PHP)。

為了防止會話固定攻擊,必須要重新生成 Session ID。在發生這種攻擊時,攻擊者並非像大多數其他基於 Session 的攻擊那樣收集受害者的 Session ID,而是在受害用戶的 Web 瀏覽器上設置 Session ID,並且與用 HTTP 協議還是 HTTPS 協議沒有關系。這種防護措施可以緩解其他同樣可啟動會話固定攻擊的 Web 漏洞的不利影響,比如拆分 HTTP 響應或 XSS(請參閱此處此處)。

還有一條補充建議,即在身份認證前后使用不同的 Session ID 或 Token 名稱(或 Session ID 集),以便 Web 應用程序可同時對匿名用戶和認證用戶都進行跟蹤記錄,而不會有泄露 Session 或穿越兩種狀態綁定用戶 Session 的風險。

如果 Web 應用程序采用 Cookie 作為 Session ID 的交換機制,並且為單個 Session 設置了多個 Cookie,則 Web 應用程序必須在允許訪問用戶 Session 之前對全部 Cookie 進行校驗(並強行設置他們之間的關系)。

很常見的做法就是,在未經認證之前(Pre-authentication),Web 應用程序通過 HTTP 協議設置用戶 Cookie,以便對未認證(或匿名)用戶進行跟蹤記錄。一旦用戶在 Web 應用程序中通過了身份認證,則會通過 HTTPS 協議設置新的認證后(Post-authentication)的安全 Cookie,並為這兩種身份的 Cookie 和用戶 Session 建立綁定關系。如果 Web 應用程序不為已認證 Session 對兩種身份的 Cookie 進行校驗,則攻擊者即可利用認證前不受保護的 Cookie 訪問認證后的用戶 Session 了。請參閱此處此處

應盡量避免在同一 Web 應用程序中為不同路徑或域使用相同的 Cookie 名稱,因為這會增加解決方案的復雜性,並可能會引入作用域問題(Scoping Issue)。

Session 到期(Session Expiration)

為了盡量縮短攻擊者能在活動 Session 上發起攻擊並劫持的時間區間,必須為每個 Session 設置到期時間,讓 Session 具備確定的存活時長。若 Web 應用程序的 Session 到期時間設置不當,將會增加其他 Session 攻擊的暴露機會。因為攻擊者要能重用合法 Session ID 並劫持關聯的 Session ,則該 Session 必須是在活動狀態下的。

Session 間隔越短,攻擊者必須利用合法 Session ID 的時間就越短。 Session 的到期時間必須根據 Web 應用程序的目的和特性進行設置,還要在安全性和可用性之間取得平衡。這樣用戶 Session 才不會頻繁過期,他才能在 Web 應用程序中順暢地完成操作。

空閑超時時間(Idle Timeout)和絕對超時時間(Absolute Timeout)都高度依賴於 Web 應用程序及其數據的重要程度。對於高價值應用程序而言,常用的空閑超時范圍為2-5分鍾,低風險應用則常為15-30分鍾。

Session 到期時,Web 應用程序必須采取主動措施讓客戶端和服務器兩端的 Session 均失效。從安全角度來看,服務器端的失效是最要緊和強制性的。

對於絕大多數 Session 交換機制而言,客戶端能讓 Session ID 失效的操作都是基於清除 Token 值的。比如要讓 Cookie 失效,推薦給 Session ID 賦一個空(或無效)值,並將 Expires(或 Max-Age)屬性置為過去的日期(如果用的是持久性 Cookie):Set-Cookie: id=; Expires=Friday, 17-May-03 18:45:00 GMT

為了在服務器端關閉 Session 並使其失效,Web 應用程序必須在 Session 到期時采取主動操作,或者用戶主動用 Session 管理機制提供的函數和方法進行簽退。這些函數有 HttpSession.invalidate()(J2EE)、Session.Abandon()(ASP .NET)、session_destroy()/unset()(PHP)。

Session 自動到期(Automatic Session Expiration)

空閑超時時間(Idle Timeout)

所有 Session 都應設置空閑或不活動的超時時間。空閑超時時間定義了 Session 在沒有活動的情況下將會保持活躍的時長,自 Web 應用程序接受到某 Session ID 的上次HTTP 請求以來,如果超過了已定義的空閑時長則會關閉 Session 並使其失效。

空閑超時時間限制了攻擊者猜測並使用其他用戶合法 Session ID 的時機。但如果攻擊者能夠劫持某現有 Session ,則空閑超時時間就無法限制攻擊者的操作,因為他可以定期在 Session 上生成活躍操作以保持更長的 Session 活躍時間。

必須在服務器端強制實施 Session 超時管理和到期機制。如果用客戶端來強制設置 Session 超時時間,比如用 Session Token 或其他客戶端參數來記錄參照時間(如自登錄時間以來的分鍾數),則攻擊者可能會操縱這些參數來延長 Session 的持續時間。

絕對超時時間(Absolute Timeout)

無論是否活躍,所有 Session 都應該設置絕對超時時間。絕對超時時間定義了某 Session 可以保持活躍的最大時長,自該 Session 第一次由 Web 應用程序創建開始計算;超過此預定義的絕對時長后, Session 將會關閉並失效。該 Session 失效之后,用戶會被強制要求在該 Web 應用程序中再次(重新)進行身份認證並建立一個新 Session。

Session 的絕對超時時間限制了攻擊者使用被劫持 Session 及模擬受害用戶的時長。

更新超時時間(Renewal Timeout)

或者,Web 應用程序可以再多設置一項更新超時時間,更新超時之后 Session ID 會在用戶 Session 期間進行自動更新,並且與 Session 是否活動無關,因此也與空閑超時時間的設置無關。

自第一次創建 Session 開始,經過指定時長之后,Web 應用程序可以為用戶 Session 重新生成新的 ID,並嘗試在客戶端上設置或更新它。在客戶端得知新 ID 並開始使用它之前,先前的 Session ID 值仍會有效一段時間,以留出一定的安全時間間間隔(Safety Interval)。此時,如果客戶端在當前 Session 內切換到新的 ID,則應用程序應讓先前的 ID 失效。

即使受害用戶的 Session 仍處於活躍狀態,此方案也可以最大限度地減少已有 Session ID 可被用於劫持用戶 Session 的時間,這個 ID 很可能已被攻擊者獲取到了。雖然每次更新超時時間到期后,在 Session 存續期內其關聯的 Session ID 值都會透明地定期更新,但是用戶 Session 在合法的客戶端上仍會保持存活和打開狀態。因此,更新超時時間設置與空閑超時時間和絕對超時時間形成了互補,尤其是當絕對超時時間明顯過長時(比如有個應用程序需要用戶 Session 長期保持打開狀態)。

根據實現的方式不同,以下競態條件是有可能存在的。在更新超時時間剛剛到期時,持有先前合法 Session ID 的攻擊者搶在受害用戶之前發送請求,並且搶先獲得了已更新的 Session ID。至少在這種情況下,受害用戶可能會得知此次攻擊,因為其 Session 會突然終止,原因是與其關聯的 Session ID 不再有效了。

Session 手動到期(Manual Session Expiration)

Web 應用程序應該提供一種機制,以便對安全性很敏感的用戶能在用完 Web 應用程序之后主動關閉其 Session。

簽退按鈕(Logout Button)

Web 應用程序必須提供一個明顯可見的、易於訪問的簽退(Logout)(注銷、退出或關閉 Session)按鈕,該按鈕可出現在 Web 應用程序的頁面頭部或菜單上,並且從每個 Web 應用程序資源和頁面均可訪問到,以便用戶隨時可以手動關閉 Session。正如 Session 到期 一節所述,Web 應用程序必須至少能在服務器端讓 Session 失效。

注意

不幸的是,並非所有 Web 應用程序都能很方便地讓用戶關閉其當前 Session。因此,客戶端的增強功能可以盡力提供關閉手段,讓嚴謹的用戶能夠保護他們的 Session。

Web 瀏覽內容緩存(Web Content Caching)

即使在 Session 關閉以后,通過 Web 瀏覽器的緩存也有可能訪問到 Session 內交換的私密或敏感數據。因此,Web 應用程序必須對通過 HTTP 和 HTTPS 協議交換的所有 Web 傳輸數據采用限制性(Restrictive)緩存指令。比如 Cache-ControlPragma HTTP 頭,並且在所有或至少是敏感頁面上加上等價的 META 標記。

如果 Web 應用程序的內容允許緩存,則絕不允許對 Session ID 進行緩存,這與 Web 應用程序定義的緩存策略無關。因此強烈建議采用 Cache-Control: no-cache="Set-Cookie, Set-Cookie2" 指令,以便讓 Web 客戶端不對 Session ID 進行緩存,參見此處

Session 管理可利用的其他客戶端防護措施(Additional Client-Side Defenses for Session Management)

除了上述 Session 管理防護措施之外,Web 應用程序還可以利用客戶端的其他一些措施作為補充。客戶端防護措施(通常采用 JavaScript 檢查和驗證的形式)並非刀槍不入(Bullet Proof),而是很容易被訓練有素的攻擊者擊破,但卻可以多加一層入侵者無法繞開的防御措施。

初次登錄超時(Initial Login Timeout)

Web 應用程序可以用登錄頁面中的 JavaScript 代碼來估算和計量自頁面加載及授予 Session ID 之后的時長。如果在指定時長之后再嘗試登錄,則客戶端代碼可以通知用戶已經超過了登錄最大時長並重新加載登錄頁面,從而能獲取一個新的 Session ID。

這種額外的防護機制試圖強制更新未認證之前的 Session ID,從而避免受害者重用之前同一台計算機的用戶(或手動設置)的 Session ID,在會話固定攻擊時就會發生這種情況。

在 Web 瀏覽器窗口關閉事件中強行簽退 Session(Force Session Logout On Web Browser Window Close Events)

Web 應用程序可以用 JavaScript 代碼捕獲所有 Web 瀏覽器 Tab 頁或窗口的關閉(甚至返回)事件,並在關閉 Web 瀏覽器之前采取適當的操作來關閉當前 Session,可以是模擬用戶通過簽退按鈕手動關閉 Session。

禁用 Web 瀏覽器的跨 Tab 頁 Session(Disable Web Browser Cross-Tab Sessions)

只要用戶登錄成功且 Session 一經建立,如果對同一個 Web 應用打開了新的 Web 瀏覽器 Tab 頁或窗口,Web 應用程序就可以用 JavaScript 代碼強制用戶重新進行身份認證。Web 應用程序不希望讓多個 Web 瀏覽器 Tab 頁或窗口共享同一個 Session。因此,該應用程序盡力強迫 Web 瀏覽器不要在多個窗口之間共享相同的 Session ID。

注意

如果 Session ID 是通過 Cookie 交換的,則上述防護機制就無法實現,因為 Cookie 是被 Web 瀏覽器的所有 Tab 頁/窗口共享的。

客戶端自動簽退(Automatic Client Logout)

在空閑超時時間到期后,Web 應用程序可以在所有(或關鍵)頁面中用 JavaScript 代碼自動簽退客戶端 Session,比如可讓用戶重定向到簽退頁面(以上提到過的簽退按鈕用到的同一個資源)。

用客戶端代碼增強服務器端空閑超時功能存在一個好處,即用戶可以知曉 Session 已經因為沒有活動而結束了,甚至可以通過倒計時和警告信息的方式提前得到 Session 即將到期的通知。如果 Session 在服務器端默默地過期,那些需要大量錄入數據的網頁就會丟失工作成果,這種用戶友好的方式則有助於避免這種情況。

Session 攻擊檢測(Session Attacks Detection)

Session ID 猜測和暴力破解檢測(Session ID Guessing and Brute Force Detection)

如果攻擊者試圖猜測或暴力破解合法的 Session ID,他需要用來自單個(或一組)IP 地址的不同 Session ID 對目標 Web 應用程序發起一連串的多次請求。此外,如果攻擊者試圖分析 Session ID 的可預測性(比如用統計學分析),他需要針對目標 Web 應用程序從單個(或一組)IP 地址發起一連串的多次請求以收集新的合法 Session ID。

依據對不同 Session ID 進行收集(或使用)的次數,Web 應用程序必須有能力檢測到上述兩種情況,並對違規 IP 地址發出警告並阻止(Block)訪問。

檢測 Session ID 異常(Detecting Session ID Anomalies)

Web 應用程序應該重點關注與 Session ID 有關的異常檢測,比如被操縱的 ID。 OWASP AppSensor 項目 提供了一種框架和方法,可在 Web 應用程序中實現內置的入侵檢測功能,該項目以設置多個檢測點並查看響應操作的形式專注於檢測異常和意外行為。有時,業務邏輯的細節和高級算法(Intelligence)只能由 Web 應用程序內部獲取,用外部保護層無法得知。可以在內部建立多個與 Session 相關的檢測點,比如修改或刪除已有 Cookie 時、已加入新的 Cookie 時、重新使用來自其他用戶的 Session ID 時、Session 期間用戶位置或 User-Agent 發生變化時。

把 Session ID 與其他屬性綁定(Binding the Session ID to Other User Properties)

為了檢測(某些情況下則是防止)用戶的錯誤行為和 Session 劫持,強烈建議將 Session ID 與其他用戶端或客戶端屬性綁定,比如客戶端 IP 地址、User-Agent 信息或基於客戶端的數字證書。如果 Web 應用程序在已建立的 Session 當中檢測到這么多不同屬性中有任何更改或異常,那就是很不錯的企圖操縱和劫持 Session 的指示,這點證據足可用於發出警告並終止可疑 Session 了。

雖然 Web 應用程序無法用上述屬性可靠地防御 Session 攻擊,但他們大大增加了 Web 應用程序的檢測(和保護)能力。當然,訓練有素的攻擊者能夠通過復用分配給受害用戶的相同 IP 地址來跳過這些控制,復用方法可以是共享同一網絡(在 NAT 環境中很常見,如 Wi-Fi 熱點);或者使用相同的 Web 代理出口(Outbound)(在公司環境中很常見);或是手動修改其 User-Agent 字段,使其看起來與受害用戶完全一樣。

用日志記錄 Session 的生命周期:監控 Session ID 的創建、使用和銷毀過程(Logging Sessions Life Cycle: Monitoring Creation, Usage, and Destruction of Session IDs)

Web 應用程序應該提高日志記錄能力,將有關 Session 全生命周期的信息納入日志。尤其建議要記錄 Session 相關的事件,如 Session ID 的創建、續期和銷毀,以及以下過程中 Session ID 的使用細節:登錄和簽退操作、 Session 內的權限級別更改、超時到期、非法 Session 活動(當檢測到時)和 Session 存續期間的關鍵業務操作。

日志的細節可以包括:時間戳、源IP地址、請求的 Web 目標資源(以及 Session 操作中涉及的資源)、HTTP 頭(含 User-Agent 和 Referer 字段)、GET 和 POST 參數、錯誤代碼和信息、用戶名(或用戶 ID),再加上 Session ID(Cookie、URL、GET、POST 等)。

為了保護 Session 日志免遭本地或遠程的 Session ID 泄露及未經授權的訪問,日志中不應包含 Session ID 之類的敏感數據。不過,某些 Session 相關(Session-specific)信息還是必須記入日志的,以便將日志條目與相關 Session 相關聯。建議記錄 Session ID 的加鹽哈希值(Salted-hash)而不是 Session ID 本身,這樣既能在日志中關聯上 Session 相關信息,又不會暴露 Session ID。

特別地,Web 應用程序必須對管理界面提供全面仔細的保護,因為管理界面能夠管理當前所有的活動 Session 。通常,這些管理界面是供后台支持人員用來解決 Session 有關問題甚至常見問題的,方式就是扮演用戶角色並像用戶那樣看待 Web 應用程序。

Session 日志已成為 Web 應用程序入侵檢測的主要數據源之一,並且在檢測到(一次或多次)攻擊時,入侵防護系統也可以根據 Session 日志來自動終止 Session 及禁用用戶帳戶。如果啟用了主動防護,則防護動作也必須記錄下來。

多 Session 同時登錄(Simultaneous Session Logons)

是否允許同一用戶同時進行多次登錄,且來自相同或不同的客戶端 IP 地址,這是在設計 Web 應用程序時就要確定的。如果 Web 應用程序不希望多個 Session 同時登錄,則每次新的身份認證事件之后都必須采取有效行動,自動終止先前的合法 Session ,或者向用戶問清楚必須存活的 Session 有哪些(舊的、新的還是兩者都要)。

建議 Web 應用程序添加供用戶使用的功能,使其能隨時檢查活動 Session 的詳細信息、監控並發登錄的信息並向用戶告警、提供用戶手動遠程終止 Session 的功能,以及記錄多個客戶端的詳細信息以跟蹤賬戶活動的歷史(日志 Logbook),這些詳細信息諸如 IP 地址、User-Agent 數據、登錄日期和時間、空閑時間等。

Session 管理 WAF 防護(Session Management WAF Protections)

在某些情況下,Web 應用程序的源代碼或是不可用的,或是無法修改的,或者為實現上述多項安全建議和最佳實踐所需的改動要對 Web 應用程序的架構進行全部重新設計,因而無法在短期內輕松實現修改。

在這些情況下,為了補充 Web 應用程序的防御措施,也為了讓 Web 應用程序盡可能安全,建議采用外部保護手段,比如能夠降低已知 Session 管理風險的 Web 應用程序防火牆(WAF,Web Application Firewall)。

WAF 提供了檢測和防護基於 Session 攻擊的功能。一方面,WAF 強制在 Cookie 上應用安全屬性,比如 SecureHttpOnly 標志、在 Web 應用程序所有設置新 Cookie 的響應頭字段 Set-Cookie 中設置簡單的重寫規則。

另一方面,WAF 還可以實現更多高級功能:允許 WAF 跟蹤 Session 及對應 Session ID,針對會話固定攻擊采取全類別防護(在檢測到權限變動時更新客戶端的 Session ID),強制要求會話保持(Sticky Session)(對 Session ID 與其他客戶端屬性之間的關系進行校驗,如 IP 地址或 User-Agent 信息),管理 Session 過期行為(強制客戶端和 Web 應用程序全都終止 Session )。

開源的 ModSecurity WAF 再加上 OWASP 核心規則集,已能提供的功能包括:檢測並設置 Cookie 安全屬性的能力、防護 Session 固定攻擊的對策、為強制要求會話保持而進行的 Session 跟蹤功能。

作者及主要編輯人員(Authors and Primary Editors)

Raul Siles (DinoSec) - raul@dinosec.com


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM