原創(chuàng) by fancyf(fancyray)
我做這個(gè)實(shí)驗(yàn)是因?yàn)閔ttp://community.csdn.net/expert/topic/3927/3927012.xml?temp=.3752405
最初我想,.net的驗(yàn)證應(yīng)該是比較安全的吧,生成的cookie也應(yīng)該與這臺(tái)電腦的獨(dú)特的參數(shù)相關(guān),拿到另一臺(tái)電腦上就應(yīng)該無效了。那么是不是一個(gè)用戶名對應(yīng)一個(gè)cookie值呢?是否能夠通過偽造cookie值來騙過表單驗(yàn)證呢?做一番試驗(yàn)。
web.config修改如下:
<authentication mode="forms">
<forms name="mylab" loginurl="/login.aspx">
<credentials passwordformat="clear">
<user name="fancyray" password="fancyray"/>
</credentials>
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
login.aspx只有一個(gè)用戶名輸入框txtusername、一個(gè)密碼輸入框txtpassword和一個(gè)提交按鈕,click事件如下:
if (formsauthentication.authenticate(this.txtusername.text, this.txtpassword.text))
{
formsauthentication.redirectfromloginpage(this.txtusername.text, true);
}
else
{
response.write("login denied");
}
借助iehttpheaders(http://www.blunck.info/)可以看到,通過驗(yàn)證后增加了一個(gè)類似這樣的cookie:
mylab=3ff83247c29eb5d14d61f389d453eee0586b94e27609c321b017be7b88d1a94d249996428a7a18f5c2d69f3c4dd2b88c00172cafb0b4b4ed8784db62d1d61bcc0c786b4ea7868fc6
看來這就是加密以后的cookie了。下面要換一臺(tái)電腦,直接將這個(gè)值設(shè)置為cookie,看看是否需要forms驗(yàn)證。
在login.aspx頁面中加上這樣一句話:
<script language=javascript>
document.cookie="mylab=3ff83247c29eb5d14d61f389d453eee0586b94e27609c321b017be7b88d1a94d249996428a7a18f5c2d69f3c4dd2b88c00172cafb0b4b4ed8784db62d1d61bcc0c786b4ea7868fc6";
</script>
這樣只要一打開login.aspx頁面就會(huì)自動(dòng)加入這個(gè)cookie。
另一臺(tái)電腦:輸入同一個(gè)webapplication下的另外一個(gè)頁面(應(yīng)該會(huì)自動(dòng)跳轉(zhuǎn)到login.aspx頁面)http://10.0.0.7/upload.aspx,這時(shí)成功跳轉(zhuǎn)到了http://10.0.0.7/login.aspx?returnurl=%2fupload.aspx,正常。這時(shí)cookie的值應(yīng)該已經(jīng)生效了。那么我們再輸入剛才那個(gè)頁面的網(wǎng)址http://10.0.0.7/upload.aspx!
按照我的猜想,肯定還會(huì)跳到login.aspx頁面的,因?yàn)槟莻€(gè)cookie是在另一臺(tái)電腦上生成的。實(shí)際呢,沒有跳轉(zhuǎn)!完整地顯示出了upload.aspx的內(nèi)容!而我們根本沒有在這臺(tái)電腦上登錄,甚至我們連用戶名都不知道!
我回到10.0.0.7這臺(tái)電腦在upload.aspx頁面的page_load()第一行添了一句:response.write(user.identity.name);,在另一臺(tái)電腦上刷新顯示出來了的upload.aspx,結(jié)果也出現(xiàn)了fancyray,正是我的用戶名。
這說明,cookie的加密不依賴于登錄的電腦。也就是說,一旦你的cookie被別人獲得,他就有可能獲得你在這臺(tái)服務(wù)器上的權(quán)限。
那么cookie的這個(gè)值是怎么來的呢?黑客是否可能不通過窮舉就得到這個(gè)值呢?
我們先來看看cookie中到底存儲(chǔ)了一些什么,以及怎樣進(jìn)行的加密。reflactor(http://www.aisto.com/roeder/dotnet)上場!
public static void setauthcookie(string username, bool createpersistentcookie, string strcookiepath)
{
formsauthentication.initialize();
httpcontext.current.response.cookies.add(formsauthentication.getauthcookie(username, createpersistentcookie, strcookiepath));
}
public static httpcookie getauthcookie(string username, bool createpersistentcookie, string strcookiepath)
{
formsauthentication.initialize();
if (username == null)
{
username = "";
}
if ((strcookiepath == null) || (strcookiepath.length < 1))
{
strcookiepath = formsauthentication.formscookiepath;
}
formsauthenticationticket ticket1 = new formsauthenticationticket(1, username, datetime.now, createpersistentcookie ? datetime.now.addyears(50) : datetime.now.addminutes((double) formsauthentication._timeout), createpersistentcookie, "", strcookiepath);
string text1 = formsauthentication.encrypt(ticket1);
formsauthentication.trace("ticket is " + text1);
if ((text1 == null) || (text1.length < 1))
{
throw new httpexception(httpruntime.formatresourcestring("unable_to_encrypt_cookie_ticket"));
}
httpcookie cookie1 = new httpcookie(formsauthentication.formscookiename, text1);
cookie1.path = strcookiepath;
cookie1.secure = formsauthentication._requiressl;
if (ticket1.ispersistent)
{
cookie1.expires = ticket1.expiration;
}
return cookie1;
}
cookie中存儲(chǔ)的值就是里面的text1,text1是由string text1 = formsauthentication.encrypt(ticket1);生成的,所以text1里面的信息就是ticket1了。formsauthenticationticket的構(gòu)造函數(shù)原形為:
public formsauthenticationticket(int version, string name, datetime issuedate, datetime expiration, bool ispersistent, string userdata, string cookiepath)
里面有用戶名、生成ticket1的時(shí)間和過期時(shí)間。
看到這里我不禁打了一個(gè)冷顫。ticket1實(shí)際上只用到了用戶名一個(gè)關(guān)鍵信息,連密碼都沒有用!這樣豈不是任何一個(gè)用戶的ticket1都可以輕易的制造出來嗎?只要通過formsauthentication.encrypt(ticket1)就得到了cookie的值,來偽裝成任何一個(gè)用戶?太可怕了。現(xiàn)在只能寄希望于encrypt這個(gè)函數(shù)了。看看它的實(shí)現(xiàn):
public static string encrypt(formsauthenticationticket ticket)
{
if (ticket == null)
{
throw new argumentnullexception("ticket");
}
formsauthentication.initialize();
byte[] buffer1 = formsauthentication.maketicketintobinaryblob(ticket);
if (buffer1 == null)
{
return null;
}
if (formsauthentication._protection == formsprotectionenum.none)
{
return machinekey.bytearraytohexstring(buffer1, 0);
}
if ((formsauthentication._protection == formsprotectionenum.all) || (formsauthentication._protection == formsprotectionenum.validation))
{
byte[] buffer2 = machinekey.hashdata(buffer1, null, 0, buffer1.length);
if (buffer2 == null)
{
return null;
}
formsauthentication.trace("encrypt: mac length is: " + buffer2.length);
byte[] buffer3 = new byte[buffer2.length + buffer1.length];
buffer.blockcopy(buffer1, 0, buffer3, 0, buffer1.length);
buffer.blockcopy(buffer2, 0, buffer3, buffer1.length, buffer2.length);
if (formsauthentication._protection == formsprotectionenum.validation)
{
return machinekey.bytearraytohexstring(buffer3, 0);
}
buffer1 = buffer3;
}
buffer1 = machinekey.encryptordecryptdata(true, buffer1, null, 0, buffer1.length);
return machinekey.bytearraytohexstring(buffer1, buffer1.length);
}
看到了machinekey這個(gè)詞,終于松了一口氣。看來加解密過程是與服務(wù)器的參數(shù)有關(guān)系。也就是說,服務(wù)器上有自己的密鑰,只有用這個(gè)密鑰才能進(jìn)行cookie的加解密。如果不知道這個(gè)密鑰,別人是無法偽造cookie的。
看來cookie還是安全的,在你的電腦沒有被入侵的前提下。與其他任何信息一樣,所需注意的僅僅是網(wǎng)絡(luò)傳輸中的安全性了。
cookie的這個(gè)值和sessionid一樣,都是一旦被猜中就可能引發(fā)安全問題。但又與sessionid有區(qū)別,因?yàn)閟essionid總是短暫的,而cookie的值卻有可能是永遠(yuǎn)有效的。cookie值的長度也讓我們稍稍放了一點(diǎn)心。
還有一個(gè)問題不容忽視。雖然cookie的值的生成與具體的時(shí)間有關(guān),也就是我注銷后再次登陸所生成的cookie是不一樣的,但是一個(gè)合法的cookie值是永久有效的,不受是否改變密碼及時(shí)間的影響。也就是說,我上一次生成的cookie在我注銷以后拿到另一臺(tái)電腦上仍然可以用,只要服務(wù)器的machinekey不變。的確是個(gè)安全隱患。我們也只能說:“cookie的值很長,要窮舉到一個(gè)有效的cookie在有生之年是辦不到的”來找一些安慰。密碼可以通過頻繁的更改來進(jìn)一步減小窮舉到的可能性,但合法的cookie卻無法更改。密碼是唯一的,但合法的cookie值卻不是唯一的。這一切總讓人覺得不太放心。
也許擔(dān)心是多余的,因?yàn)殡娮雍灻⒆C書都是建立在“窮舉要付出很大代價(jià)”的基礎(chǔ)上的,要是考慮“碰巧被窮舉到”的話,安全就不復(fù)存在了。相信在一般的安全領(lǐng)域,forms生成的cookie的安全級別還是足夠的。
放心地去用吧!(又一篇毫無價(jià)值的文章,當(dāng)你沒看過好了)