asp.net|cookie|session
瀏覽器的會話使用儲存在 SessionID 屬性中的唯一識別碼進行標識。會話 ID 使 ASP.NET 應用程式能夠將特定的瀏覽器與 Web 服務器上相關的會話資料和資訊相關聯。會話 ID 的值在瀏覽器和 Web 服務器間通過 Cookie 進行傳輸,如果指定了無 Cookie 會話,則通過 URL 進行傳輸。
ASP.NET 通過自動在頁的 URL 中插入唯一的會話 ID 來保持無 Cookie 工作階段狀態。例如,下面的 URL 已被 ASP.NET 修改,以包含唯一的會話 ID lit3py55t21z5v55vlm25s55:
http://www.example.com/s(lit3py55t21z5v55vlm25s55)/orderform.aspx
如果一個包含無 Cookie SessionID 的連結被多個瀏覽器共用時(可能通過搜尋引擎或其他程式),此行為可能導致對會話資料的意外共用。可以通過禁用工作階段識別項的回收來降低多個用戶端共用工作階段資料的可能性。為此,將 sessionState 配置元素的 regenerateExpiredSessionId 屬性設定為 true。這樣,在使用已到期的會話 ID 發起無 Cookie 會話請求時,將產生一個新的會話 ID。
——摘自 MSDN
.NET2.0中我們已可以通過重寫SessionIDManager 類來改變SessionID 的產生機制和驗證方法來防止會話資料的意外共用(即出現多個瀏覽器被識別為同一個會話,共用一個Session),可在.NET1.1中卻沒有相關的類讓我們改變SessionID 的產生機制(封裝死了),但受一篇文章的啟發,我們可以在SessionID 產生之後對它進行處理。文章是老外寫的,由於本人閱讀能力有限,偶可沒時間去看一大版唧唧歪歪的鷹文,直接下了代碼來看。還好代碼不算多,思路也很清晰,大概瞭解了他實現重寫SessionID的原理,我改了下在無Cookie 會話中完美實現了。
相關代碼
using System;
using System.Web;
using System.Web.SessionState;
using System.Web.Security;
using System.Configuration;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Globalization;
using System.Text;
public class SecureSessionModule : IHttpModule
{
private static string _ValidationKey = null;
public void Init (HttpApplication app)
{
if (_ValidationKey == null)
_ValidationKey = GetValidationKey ();
app.AcquireRequestState+=new EventHandler(app_AcquireRequestState);
}
void app_AcquireRequestState (Object sender, EventArgs e)
{
_ValidationKey=GetValidationKey();//每天產生一個KEY提高安全性
HttpContext current = ((HttpApplication) sender).Context;
//將處理後的SessionID存在Session["ASP.NET_SessionID"]中
string sessionid = GetSession (current, "ASP.NET_SessionID");
if (sessionid != null)
{
if (sessionid.Length <= 24)
RedirectUrl(current);
string id = sessionid.Substring (0, 24);
string mac1 = sessionid.Substring (24);
string mac2 = GetSessionIDMac (id, current.Request.UserHostAddress, current.Request.UserAgent, _ValidationKey);
// 使用者用戶端資訊發生的變化,比對失敗
if (String.CompareOrdinal(mac1, mac2) != 0)
{
RedirectUrl(current);
}
}
else
{
RedirectUrl(current);
}
}
private void RedirectUrl(HttpContext current)
{
//重新導向頁面以重建新的SessionID
current.Response.Redirect(current.Request.Url.ToString(),true);
}
private string GetValidationKey ()
{
string key = DateTime.Now.ToShortDateString();
return key;
}
private string GetSession (HttpContext current, string name)
{
object id = FindSession(current.Session,name);
if (id == null)
{
// 將使用者用戶端資訊加密儲存在Session中以便比對
id= current.Session.SessionID+GetSessionIDMac (current.Session.SessionID, current.Request.UserHostAddress,
current.Request.UserAgent, _ValidationKey);
current.Session[name] = id;
}
return id.ToString();
}
private object FindSession (HttpSessionState session, string name)
{
return session[name];
}
private string GetSessionIDMac (string id, string ip, string agent, string key)
{
StringBuilder builder = new StringBuilder (id, 512);
builder.Append (ip);
builder.Append (agent);
using (HMACSHA1 hmac = new HMACSHA1 (Encoding.UTF8.GetBytes (key)))
{
return Convert.ToBase64String (hmac.ComputeHash (
Encoding.UTF8.GetBytes (builder.ToString ())));
}
}
public void Dispose () {}
}
相關配置如下:
<configuration>
<system.web>
<httpModules>
<add name="SecureSession" type="SecureSessionModule,SecureSessionModule" />
</httpModules>
</system.web>
</configuration>
大家看了代碼後就會知道,它實現的原理主要是因為不可能有相同IP電腦用戶端同時訪問一台伺服器,當出現SessionID相同但他們用戶端資訊不同時就自動將後一個訪問的用戶端重新導向以建立一個會話。
遺憾的是在WAP上應用時就有問題了,由於用戶端資訊沒IP唯一標識(移動不給手機號資訊了),所以如果相同型號的手機訪問時就無法區分,不知哪位高人有沒更好的解決辦法,還望不吝賜教