探索ASP.NET Forms驗(yàn)證的相關(guān)安全性問(wèn)題
ASP.NET Forms驗(yàn)證主要是為了防止Forms被破解危害網(wǎng)站的安全,今天我們將從簡(jiǎn)單的Forms開(kāi)始講述,最后講解危機(jī)將帶來(lái)什么后果。
ASP.NET提供了內(nèi)置的登錄驗(yàn)證,最為常用的就是Forms驗(yàn)證。講解如何配置的文章非常多,這里就不再講如何配置使用這個(gè)驗(yàn)證的方式了。下面講講其在安全性上存在的一些被忽視的問(wèn)題。其實(shí)它本身沒(méi)有問(wèn)題,而使用的方式上會(huì)附帶出來(lái)一些問(wèn)題。
本文將分三部分講實(shí)際應(yīng)用中將會(huì)遇到的安全性問(wèn)題,并且加以研究,并嘗試提出解決方案。
一、簡(jiǎn)單的Forms被破解危機(jī)
二、垂直劃分站點(diǎn)的Forms被破解危機(jī)
三、危機(jī)將帶來(lái)什么后果
一、簡(jiǎn)單的Forms被破解危機(jī)
最簡(jiǎn)單的一個(gè)ASP.NET Forms驗(yàn)證,在web.config下配置節(jié)點(diǎn):
- <authentication mode="Forms">
- <forms name=".MyCookies"></forms>
- </authentication>
編寫(xiě)一個(gè)幫助類(lèi):
- CookieHelper類(lèi)
- public static class CookieHelper {
- public static string Encrypt(string name, string value) {
- FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, name, DateTime.Now, DateTime.Now.AddDays(1), true, value, "/");
- string authTicket = FormsAuthentication.Encrypt(ticket);
- return authTicket;
- }
- public static void Set(string name, string value) {
- HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, Encrypt(name, value));
- cookie.Expires = DateTime.Now.AddDays(1);
- if (HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName] == null)
- HttpContext.Current.Response.Cookies.Add(cookie);
- else
- HttpContext.Current.Response.Cookies.Set(cookie);
- }
- public static string Get() {
- if (HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName] == null)
- return null;
- else {
- return HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value;
- }
- }
- public static FormsAuthenticationTicket Decrypt(string value) {
- return FormsAuthentication.Decrypt(value);
- }
- }
建立站點(diǎn)SiteA
建立站點(diǎn)SiteB
在SiteA的頁(yè)面設(shè)置Cookie:
CookieHelper.Set("yurow", "123123");
OK!這樣,就在SiteA建立了一份Cookie,這個(gè)本身并沒(méi)有任何問(wèn)題。但是我們往往忽視了一些問(wèn)題,大家看到,我在CookieHelper類(lèi)里提供了Decrypt方法,這個(gè)方法可以解密Cookie。問(wèn)題就在于這里!怎么?不知道?那就讓貧道來(lái)跟施主解釋。在這樣的網(wǎng)站下,我進(jìn)行以下的操作步驟:
1、我注冊(cè)一個(gè)帳號(hào);
2、我用這個(gè)帳號(hào)登錄(方便起見(jiàn),我使用Firefox);
3、打開(kāi)Firebug,并且啟用該網(wǎng)站的網(wǎng)絡(luò)監(jiān)視;
4、刷新登錄后的頁(yè)面;
5、在該頁(yè)面被監(jiān)視的HTTP頭中可以看到一段Cookie密文。例如:
.MyCookie=32DDE0B4E858248037E4D082EF7E9C9BC607B7AA878F8DD
7DE7C13630A5A38FD9A9DA89B709E79F97D05DEEFC9D55A45D29051D
66955439055D01476E8659E34ABDB42FA0018020194F26618FE74E11B
這樣的字符串。
OK,在該網(wǎng)站的操作到此為止。現(xiàn)在在SiteB中建立一個(gè)頁(yè)面,中間加上一個(gè)輸入框,一個(gè)按鈕,并且編寫(xiě)以下事件:
解密代碼
- protected void Button1_Click(object sender, EventArgs e) {
- string text = TextBox1.Text;
- if (!string.IsNullOrEmpty(text)) {
- FormsAuthenticationTicket ticket = CookieHelper.Decrypt(text);
- Type type = ticket.GetType();
- PropertyInfo[] properties = type.GetProperties();
- StringBuilder sb = new StringBuilder();
- foreach (PropertyInfo propertie in properties) {
- string name = propertie.Name;
- string val = propertie.GetValue(ticket, null).ToString();
- sb.Append(name);
- sb.Append(":");
- sb.Append(val);
- sb.Append("\r\n");
- }
- //textBox2.Text = sb.ToString();
- Response.Write(sb.ToString());
- }
- }
把上面的Cookie密文,等于后面的部分復(fù)制到SiteB頁(yè)面中,點(diǎn)解密按鈕,看到了什么?
Version:1 Name:yurow Expiration:2009-9-23 19:12:44 IssueDate:2009-9-22 19:12:44 IsPersistent:True Expired:False UserData:123123 CookiePath:/
怎么樣?所有的信息都被解密了!不過(guò)好像高興地太早了,解密了自己的數(shù)據(jù)有啥用啊,又拿不到別人的Cookie密文。暫且打住,接下來(lái)先講垂直劃分站點(diǎn)安全隱患。
二、垂直劃分站點(diǎn)的Forms被破解危機(jī)
垂直劃分站點(diǎn)其外在表現(xiàn)一般是多域名的N多站點(diǎn)。比如博客園的space.cnblogs.com,news.cnblogs.com等等。而上面第一部分的描述中,貧道似乎漏掉了關(guān)于設(shè)置machineKey的問(wèn)題,那是因?yàn)橐舻竭@里來(lái)講,要是上面都說(shuō)了,現(xiàn)在講啥?
是的,我們是可以在web.config中設(shè)置
<machineKey validationKey="*********" decryptionKey="********" validation="SHA1" decryption="3DES"/>
這樣的節(jié)點(diǎn)。如果在A站點(diǎn)設(shè)置了這個(gè),除非B站點(diǎn)也設(shè)置相同KEY的節(jié)點(diǎn),否則SiteB將無(wú)法正確解密SiteA產(chǎn)生的Cookie密文。似乎一般的網(wǎng)站都設(shè)置了這個(gè),好像我們不需要為此而擔(dān)心了嘛!
是的,一般情況是這樣的。但是,很多公司的人員流動(dòng)性是較大的,而且垂直分割的站點(diǎn)中,可以接觸到web.config的人我相信是非常多的。這就能讓某些人,(當(dāng)然,不包括貧道,嘿嘿)就可以比較容易地拿到這個(gè)關(guān)鍵的數(shù)據(jù)。這個(gè)數(shù)據(jù)能干啥?那還用說(shuō)啊?我在SiteB我自己建立的站點(diǎn)的Web.config也配置上這個(gè)節(jié)點(diǎn),那就可以輕易解開(kāi)目標(biāo)網(wǎng)站的Cookie密文。為了保證這方面的安全性不得不把Cookie加密解密部分做成服務(wù),不但容易更新,而且讓盡可能少的人接觸,防止安全性上的問(wèn)題被放大。要不然,有個(gè)人離職啊,或者電腦中毒啊,最好還是要改動(dòng)改動(dòng)machineKey,否則呢?否則就有可能出問(wèn)題。出什么問(wèn)題呢?這就是下面要講的。
三、危機(jī)將帶來(lái)什么后果
加密的Key泄露,會(huì)帶來(lái)什么后果?后果很?chē)?yán)重。從上面的例子可以看到這個(gè)站點(diǎn)Cookie密文包含的關(guān)鍵信息。而是要CookieHelper類(lèi),根據(jù)這些關(guān)鍵信息,我們就可以輕易地制造出一個(gè)Cookies密文。而拿這個(gè)Cookies密文寫(xiě)入目標(biāo)網(wǎng)站的Coookies中,那么就會(huì)認(rèn)為你已經(jīng)登錄。并且這個(gè)(這里我們用的驗(yàn)證可能是Cookie保持的用戶(hù)名或者ID一類(lèi)的東西。)用戶(hù)名可以隨意偽造,也就是可以用不存在的用戶(hù)進(jìn)行發(fā)帖!如果你每次在發(fā)帖等操作進(jìn)行驗(yàn)證無(wú)疑是增加了服務(wù)器的負(fù)擔(dān),而最好的辦法當(dāng)然是不外泄加密KEY了。這種方式不當(dāng)可以偽造用戶(hù)(幾個(gè)月前我專(zhuān)門(mén)試過(guò)一些站點(diǎn)是可以的,而偽造用戶(hù)發(fā)帖會(huì)造成該論壇的某個(gè)版面甚至首頁(yè)無(wú)法訪問(wèn)),而且可以偽造成管理員的帳號(hào)。不難想象,如果用其它用戶(hù)的帳號(hào)或者管理員的帳號(hào)進(jìn)行隨意發(fā)帖,會(huì)造成怎么樣的惡劣影響了吧?
OK,意識(shí)到問(wèn)題了吧?
本文來(lái)自Birdshover的博客園文章《ASP.NET Forms驗(yàn)證的安全性問(wèn)題研究——為什么加密代碼需要配置為服務(wù)》
【編輯推薦】

















