瀏覽器的會話使用存儲在 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唯一標識(移動不給手機號信息了),所以如果相同型號的手機訪問時就無法區分,不知哪位高人有沒更好的解決辦法,還望不吝賜教
新聞熱點
疑難解答
圖片精選