我們承認這一點 — 我們對工作階段狀態這一概念是如此習以為常,以至於我們忘記了工作階段狀態是在 1997 年用 Active Server Pages (ASP) 引入的一個手段。工作階段狀態使開發人員能夠在使用者與應用程式互動這段時間內持久儲存有關該使用者的一塊資訊。特定於使用者的資訊通常會保留 20 分鐘長的時段,而每當使用者返回該網站時,該時段都將重新開始計時。
當使用者首次串連到網站時,將以記憶體塊的形式建立一個全新的工作階段狀態以存放資料,同時,還會建立一個 ID 以便將其與目前使用者唯一地聯絡起來。當下一次發出請求時,該使用者將被要求提交該會話 ID,以便檢索並正確地還原工作階段狀態。會話 ID 是 ASP 和 ASP.NET 完全自主產生的字母數字字串。使用者如何管理它並確保用每個後續請求來封裝它呢?
HTTP 協議的性質是無狀態的,並且沒有任何人試圖更改這一事實。差不多二十年以前,當 Netscape Corporation 開發它的第一個瀏覽器時,它“發明”了一種通過 HTTP 工作的持久性機制。它將其稱為 HTTP Cookie。有趣的是,電腦科學行話中的術語“Cookie”僅僅表示一塊由應用程式持有的不透明資料,它會影響使用者但永遠不會由使用者直接管理。
因此,Cookie 儲存會話的 ID,而瀏覽器則在 Web 服務器和本機使用者的電腦之間來回移動它們的內容。當啟用了 Cookie 的瀏覽器收到響應資料包時,它將尋找附加的 Cookie,並將它們的內容儲存到本地 Windows 目錄中特定檔案夾的某個文字檔中。Cookie 還包含有關該來源站點點的資訊。接下來,當瀏覽器向該網站發送請求時,它會在 Cookie 檔案夾中尋找源自該域的 Cookie。如果找到,則該 Cookie 自動附加到傳出的資料包中。該 Cookie 將命中伺服器應用程式,並在此被檢測、提取和處理。
最終,Cookie 使 Web 網站更加易於導航,因為它們在使用者體驗之上提供了必然跨越多個請求的連續性錯覺。
Cookies 是不是一個問題?
多年以來,Cookie 只被視為一種技術功能,並且在很大程度上被忽略了。幾年以前,針對 Web 安全的世界範圍的浪潮將人們的注意力集中於 Cookie 身上。Cookie 被斷定包含危險的程式,它們甚至能夠超出電腦的物理邊界來竊取有價值的資訊。
不言而喻,Cookie 不是程式,因而無法自行收集任何資訊 — 更不用說有關使用者的任何個人資訊。更加清楚的是,Cookie 是 Web 網站可以放置在使用者的電腦中以便以後檢索和重用的一段文本。所儲存的資訊是由無害的名稱-值對組成的。
要點在於,Cookie 不是標準 HTTP 規範的一部分,因此它們意味著瀏覽器和 Web 網站之間的一種協作。並非所有瀏覽器都支援 Cookie,而且更為重要的是,並非所有使用者都在他們自己的瀏覽器副本中啟用 Cookie 支援。
在曆史上,有一些 Web 網站功能是如此緊密地與 Cookie 相聯絡,以至於很難區分究竟是哪個功能最先出現。一方面,用 Cookie 對工作階段狀態管理和使用者身分識別驗證進行編碼要容易得多。另一方面,如果您觀察一下網站與用於訪問頁的瀏覽器有關的統計資訊,那麼您可能會驚訝地發現,相當一部分使用者在串連時禁用了 Cookie。這一點會對開發人員有所啟示。
總而言之,Cookie 本身並不是問題,但它們的使用無疑給予一些伺服器代碼在用戶端電腦中儲存一段資料的能力。這預示著一些潛在的安全風險和一種不夠理想的總體狀況。(在某些情況以及某些省/地區中,應用程式要求 Cookie 工作甚至是非法的。)
返回頁首
進入無 Cookie 會話
在 ASP.NET 中,無需使用 Cookie,就可以有選擇地建立必要的會話-使用者聯絡。非常有趣的是,除了以下配置設定以外,您無需在 ASP.NET 應用程式中更改任何內容即可啟用無 Cookie 會話。
ASP.NET 工作階段狀態的預設設定是在 machine.config 檔案中定義的,並且可以在應用程式根資料夾中的 web.config 檔案中重寫。通過確保上述行出現在根 web.config 檔案中,您可以啟用無 Cookie 會話。就是這樣 — 簡單而有效!
節點還可以用於配置工作階段狀態管理的其他方面,包括儲存介質和連接字串。但是,就 Cookie 而言,只需您將 cookieless 屬性設定為 true(預設設定為 false)。
請注意,會話設定是應用程式範圍的設定。換句話說,您網站中的頁要麼都將使用要麼都將不使用 Cookie 來儲存會話 ID。
當不使用 Cookie 時,ASP.NET 在哪裡儲存會話 ID 呢?在這種情況下,會話 ID 插入到 URL 內的特定位置中。顯示一個使用無 Cookie 會話的真實網站的快照。
圖 1. 使用無 Cookie 會話的 MapPoint
假設您請求了一個類似於 http://yourserver/folder/default.aspx 的頁。正如您可以從 MapPoint 快照中看到的那樣,資源名稱前面的相鄰斜杠進行了擴充,以便包含在內部填充了會話 ID 的括弧,如下所示。
http://yourserver/folder/(session ID here)/default.aspx
會話 ID 嵌入到 URL 中,並且無需在其他任何地方持久儲存它。唔,並不完全是這樣。請考慮以下方案。
您訪問了一個頁,並且被分配了一個會話 ID。接下來,您清除了同一瀏覽器樣本的地址欄,轉到另一個應用程式並且開始工作。然後,您重新鍵入了上一個應用程式的 URL,並且(猜猜看)在您進入的過程中檢索會話值。
如果您使用無 Cookie 會話,那麼當您第二次訪問該應用程式時,您將被分配一個不同的會話 ID,並且丟失以前的所有狀態。這是無 Cookie 會話的一個典型的副作用。為了瞭解其原因,讓我們進一步探討無 Cookie 會話的實現。
實現
無 Cookie 會話的實現得益於下列兩個運行時模組的努力:一個名為 SessionStateModule 的標準會話 HTTP 模組,以及一個名為 aspnet_filter.dll 的可執行檔。後者是一小段 Win32 代碼,它充當 ISAPI 篩選器。HTTP 模組和 ISAPI 篩選器實現了相同的思想,不同之處在於 HTTP 模組由Managed 程式碼組成,並且需要 ASP.NET 和 CLR 觸發才能工作。像 aspnet_filter.dll 這樣的傳統 ISAPI 篩選器是由 Internet 資訊服務 (IIS) 調用的。二者都截獲在請求處理過程中激發的 IIS 事件。
當新瀏覽器會話的第一個請求進入時,工作階段狀態模組讀取 web.config 檔案中有關 Cookie 支援的設定。如果 節的 cookieless 屬性設定為 true,則該模組產生一個新的會話 ID,通過將該會話 ID 填充到資源名稱前面的相鄰位置來分割 URL,並且使用 HTTP 302 命令將瀏覽器重新導向到新的 URL。
當每個請求到達 IIS 入口時(遠遠早於它被移交給 ASP.NET),aspnet_filter.dll 獲得了一個查看它的機會。如果該 URL 將會話 ID 嵌入到括弧中,則會提取該會話 ID 並將其複製到一個名為 AspFilterSessionId 的請求標題中。然後,重寫該 URL 以使其看起來像原來請求的資源,並且將其釋放。這一次,ASP.NET 工作階段狀態模組從請求標題中檢索會話 ID,並且通過會話-狀態綁定繼續工作。
只要該 URL 包含可用來擷取會話 ID 的資訊,無 Cookie 機制就可以很好地工作。正如您稍後將看到的那樣,這會造成一些使用限制。
讓我們研究一下無 Cookie 會話的優缺點。
返回頁首
優點
在 ASP.NET 中,會話管理和表單身分識別驗證是唯一的兩個在後台使用 Cookie 的系統功能。通過無 Cookie 會話,您現在可以部署無論使用者的有關 Cookie 的喜好設定如何都能正常工作的有狀態應用程式。然而,就 ASP.NET 1.x 而言,仍然需要使用 Cookie 來實現表單身分識別驗證。好訊息是,在 ASP.NET 2.0 中,表單身分識別驗證可以選擇以無 Cookie 方式工作。
另一個經常提出的反對 Cookie 的理由是安全性。這是一個值得予以更多關注的要點。
Cookies 是無活動能力的文字檔,因此,這些檔案可能被攻擊者替換或損壞 — 只要他們獲得了對電腦的訪問。真正的威脅並不在於 Cookie 可以在用戶端電腦上安裝什麼,而是在於它們可以向目標網站上傳什麼。Cookie 不是程式,並且永遠不會像程式那樣運行;然而,您電腦上安裝的其他軟體可以使用對 Cookie 的瀏覽器內建支援來遠程從事破壞活動。
此外,Cookie 要受到被盜竊的風險。一旦失竊,包含有價值的和私人的資訊的 Cookie 就可能將其內容泄露給惡意攻擊者,並且為其他類型的 Web 攻擊提供便利。總之,通過使用 Cookie,您將自己暴露在本可以消除的風險之中。這是真的嗎?
返回頁首
缺點
讓我們從另一個角度來考察安全性。您是否曾經聽說過工作階段劫持?如果沒有,則請閱讀一下 TechNet Magazine 文章 Theft On The Web: Prevent Session Hijacking。簡單說來,當攻擊者獲得對特定使用者的工作階段狀態的訪問時,將發生工作階段劫持。其實質是,攻擊者竊取有效會話 ID,並且使用它侵入系統和窺探資料。擷取有效會話 ID 的一種常見方式是竊取有效工作階段 Cookie。鑒於此,如果您認為無 Cookie 會話保護了您應用程式的安全,那您就完全錯了。實際上,對於無 Cookie 會話,會話 ID 直接顯示在地址欄中!請嘗試下列操作:
1.
串連到使用無 Cookie 會話的 Web 網站(例如,MapPoint)並獲得一個映射。此時,該地址儲存在工作階段狀態中。
2.
抓取 URL(直至頁名稱)。不要包括查詢字串,但請確保該 URL 包括會話 ID。
3.
將該 URL 儲存到檔案中,並將該檔案複製/發送到另一台電腦。
4.
在第二台電腦上開啟該檔案,並將該 URL 粘貼到新瀏覽器執行個體中。
5.
只要會話逾時仍然有效,就會顯示同一個映射。
通過無 Cookie 會話,可以比以往任何時候都更加容易地竊取會話 ID。
從道德的觀點來看,竊取會話是應該受到譴責的操作,我相信大家會一致認同這一點。但它是否也是有害的?這取決於工作階段狀態中實際儲存的內容。竊取會話 ID 本身並不會執行超出代碼控制範圍的操作。但是,它可能向未經授權的使用者泄露私人資料,並且使一些壞傢伙能夠執行未經授權的操作。有關如何在 ASP.NET 應用程式中阻止工作階段劫持的提示,請閱讀 Wicked Code: Foiling Session Hijacking Attempts。(而且,它並不依賴於無 Cookie 會話!)
使用無 Cookie 會話還會引起與連結有關的問題。例如,您不能在 ASP.NET 頁中具有絕對的、完整連結。如果您這樣做,那麼源自該超連結的每個請求都將被視為新會話的一部分。無 Cookie 會話要求您總是使用相對 URL,就像在 ASP.NET 回傳中一樣。僅當您可以將會話 ID 嵌入到 URL 中時,您才可以使用完整 URL。但是,既然會話 ID 是在運行時產生的,那麼您如何才能做到這一點呢?
下面的代碼中斷了該會話:
Click
要使用絕對 URL,可以藉助於一個小技巧,即,使用 HttpResponse 類上的 ApplyAppPathModifier 方法:
>Click
ApplyAppPathModifier 方法採用一個表示 URL 的字串作為參數,並且返回一個嵌入了會話資訊的絕對 URL。例如,當您需要從 HTTP 頁重新導向到 HTTPS 頁時,該技巧尤其有用。最後,請特別注意,每當您在同一個瀏覽器內部鍵入指向某個網站的路徑時,您都將丟失無 Cookie 會話的狀態。還要請您注意的是,對於行動裝置 App程式,如果裝置無法處理專門格式化的 URL,則無 Cookie 會話可能會出現問題。
返回頁首
小結
ASP.NET 中存在無 Cookie 會話的主要原因是使用者(無論出於什麼原因)可能在他們的瀏覽器中禁用了 Cookie。如果您的應用程式需要工作階段狀態,那麼無論您是否喜歡,您都必須面對這種情況。無 Cookie 會話將會話 ID 嵌入到 URL 中,並且得到了雙重結果。一方面,它們為 Web 網站提供了一種正確標識發出請求的使用者的方式。然而,另一方面,它們使會話 ID 清楚地顯現在潛在的攻擊者面前,從而使攻擊者可以輕鬆地竊取它並以您的身份進行操作。
要實現無 Cookie 會話,您無需修改自己的編程模型 — 只需在 web.config 檔案中進行簡單更改,就可以完成相關工作 — 但是,還要強烈建議您重構您的應用程式,以免在工作階段狀態中儲存有價值的資訊。同時,將會話的生存期縮短至預設的 20 分鐘以內有助於保護您的使用者和網站的安全。