C#发现之旅第九讲 ASP.NET验证码技术
袁永福 2008-5-15
系列課程說明
????為了讓大家更深入的了解和使用C#,我們將開始這一系列的主題為“C#發(fā)現(xiàn)之旅”的技術(shù)講座。考慮到各位大多是進(jìn)行WEB數(shù)據(jù)庫(kù)開發(fā)的,而所謂發(fā)現(xiàn)就是發(fā)現(xiàn)我們所不熟悉的領(lǐng)域,因此本系列講座內(nèi)容將是C#在WEB數(shù)據(jù)庫(kù)開發(fā)以外的應(yīng)用。目前規(guī)劃的主要內(nèi)容是圖形開發(fā)和XML開發(fā),并計(jì)劃編排了多個(gè)課程。在未來的C#發(fā)現(xiàn)之旅中,我們按照由淺入深,循序漸進(jìn)的步驟,一起探索和發(fā)現(xiàn)C#的其他未知的領(lǐng)域,更深入的理解和掌握使用C#進(jìn)行軟件開發(fā),拓寬我們的視野,增強(qiáng)我們的軟件開發(fā)綜合能力。
本系列課程配套的演示代碼下載地址為 http://files.cnblogs.com/xdesigner/cs_discovery.zip 。
本系列課程已發(fā)布的文章有
C#發(fā)現(xiàn)之旅第一講 C#-XML開發(fā)
C#發(fā)現(xiàn)之旅第二講 C#-XSLT開發(fā)
C#發(fā)現(xiàn)之旅第三講 使用C#開發(fā)基于XSLT的代碼生成器
C#發(fā)現(xiàn)之旅第四講 Windows圖形開發(fā)入門
C#發(fā)現(xiàn)之旅第五講 圖形開發(fā)基礎(chǔ)篇
C#發(fā)現(xiàn)之旅第六講 C#圖形開發(fā)中級(jí)篇
C#發(fā)現(xiàn)之旅第七講 C#圖形開發(fā)高級(jí)篇
C#發(fā)現(xiàn)之旅第八講 ASP.NET圖形開發(fā)帶超鏈接的餅圖
C#發(fā)現(xiàn)之旅第九講 ASP.NET驗(yàn)證碼技術(shù)
C#發(fā)現(xiàn)之旅第十講 文檔對(duì)象模型
課程說明
????大家好,在上一節(jié)課程中,我們開始了解了如何在在ASP.NET中使用圖形編程的技術(shù)。今天我們針對(duì)驗(yàn)證碼技術(shù)深入的了解圖形編程在ASP.NET中的應(yīng)用。
????驗(yàn)證碼技術(shù)是目前很多WEB程序采用的一種安全防御技術(shù)。系統(tǒng)在登錄的時(shí)候不但要輸出用戶名和密碼,還要額外輸入一種隨機(jī)生成的驗(yàn)證碼文本,此時(shí)用戶需要正確的輸入這三個(gè)信息才能登錄到系統(tǒng)中。
????由于驗(yàn)證碼技術(shù)能有效的抵御某些黑客攻擊,因此得到相當(dāng)廣泛的應(yīng)用,而且在一些C/S系統(tǒng)中也采用了這種源自WEB開發(fā)的技術(shù)。
驗(yàn)證碼原理????在現(xiàn)在的軟件運(yùn)行環(huán)境下,安全成為大部分軟件必須考慮的問題,黑客無處不在,攻擊方式日益豐富,尤其是WEB系統(tǒng)由于其開放性更是遇到嚴(yán)峻的考驗(yàn),黑客事件層出不窮,造成的損失和影響也不斷變大,對(duì)此我們軟件開發(fā)人員需要對(duì)此有相當(dāng)?shù)恼J(rèn)識(shí)并采取措施抵御各種黑客攻擊。
枚舉字典安全攻擊????在各種黑客攻擊中,很常見的就是套取用戶名和密碼,其中很多是采用枚舉字典的方式來不斷的測(cè)試用戶名和密碼。
????比如某黑客獲得一銀行賬號(hào),然后打開賬號(hào)的開戶銀行的網(wǎng)上銀行登錄界面。分析其中的HTML代碼,發(fā)現(xiàn)其頁(yè)面粗制濫造,沒有驗(yàn)證碼,沒有任何安全控制,只要求輸入銀行賬號(hào)和取款密碼就可以登錄。黑客心中大喜,馬上寫了一個(gè)程序,直接調(diào)用HTTP協(xié)議,使用程序來模擬瀏覽器向網(wǎng)上銀行服務(wù)器提交賬號(hào)和密碼嘗試登錄。由于取款密碼是6位阿拉伯?dāng)?shù)字,因此也就有一百萬種組合,黑客的電腦從六個(gè)零開始測(cè)試一直到六個(gè)九,這一定會(huì)測(cè)試出真正的密碼。黑客找到一臺(tái)寬帶高速上網(wǎng)的電腦,運(yùn)行套取取款密碼程序后就忙其他事了,假設(shè)這臺(tái)電腦1秒能測(cè)試10個(gè)密碼,于是花費(fèi)10萬秒的時(shí)間肯定能找到密碼。10萬秒也就是27小時(shí),一天多點(diǎn)的時(shí)間,實(shí)際上很可能用不了那么長(zhǎng)的時(shí)間。黑客外頭轉(zhuǎn)了一圈回來,發(fā)現(xiàn)密碼已經(jīng)找到了,于是馬上登錄網(wǎng)上銀行撈錢,或者偽造一個(gè)銀行卡去ATM機(jī)上提取現(xiàn)金。也就是說黑客最多花了一天時(shí)間即可獲得數(shù)目不可預(yù)知的非法收入。
驗(yàn)證碼防御????網(wǎng)上銀行可以有很多手段來抵御黑客攻擊,比如使用ActiveX控件代替標(biāo)準(zhǔn)的文本框來輸入賬號(hào)和密碼,可以使用USB接口的密碼盤來進(jìn)行數(shù)據(jù)加密和檢測(cè),或者使用一個(gè)客戶端程序代替瀏覽器來登錄網(wǎng)上銀行。但這些是客戶端技術(shù),千千萬萬的黑客可以操著各種手術(shù)刀來解剖這些技術(shù),從根本上說客戶端技術(shù)是不可靠的。
????相對(duì)而言采用服務(wù)器端技術(shù)就比較安全了。比如發(fā)現(xiàn)密碼連續(xù)錯(cuò)誤3次即鎖定賬戶,1天后才能登錄;也可以使用驗(yàn)證碼技術(shù)來很大程度的抵御枚舉字典套取密碼的攻擊。
????現(xiàn)有一個(gè)新的網(wǎng)上銀行,和舊網(wǎng)銀差不多,但采用了驗(yàn)證碼技術(shù),用戶登錄時(shí)除了要輸入賬號(hào)和取款密碼,瀏覽器還顯示一個(gè)圖片,里面顯示了一些潦草的字符,用戶需要辨認(rèn)這些字符然后再輸入進(jìn)去,瀏覽器向服務(wù)器提交表單時(shí)會(huì)附加用戶輸入的驗(yàn)證碼,服務(wù)器接受表單數(shù)據(jù)后除了校驗(yàn)賬號(hào)和取款密碼后,還要檢查驗(yàn)證碼是否輸入正確,若登錄信息校驗(yàn)失敗,則服務(wù)器端則會(huì)提示重新登錄,而且還生成包含隨機(jī)內(nèi)容的新的驗(yàn)證碼,用戶在次登錄時(shí)又得重新識(shí)別新的驗(yàn)證碼了。
????由于正確的驗(yàn)證碼文本是保存在服務(wù)器上的,客戶端的黑客程序不可能獲得,驗(yàn)證碼的內(nèi)容是隨機(jī)的,黑客程序也無法找到規(guī)律,只能辨認(rèn)從服務(wù)器端發(fā)出的包含驗(yàn)證碼的圖片來獲得驗(yàn)證碼。這里就體現(xiàn)了電腦和人腦的差別了,人腦在圖形識(shí)別方面遠(yuǎn)遠(yuǎn)超過了目前的電腦,服務(wù)器端使用一些技術(shù)生成的書寫潦草,充滿隨機(jī)分布的雜點(diǎn)的圖片,人腦是可以相當(dāng)容易的識(shí)別的,但目前的電腦是難以識(shí)別的。黑客程序無法識(shí)別驗(yàn)證碼,只能顯示圖片讓黑客親自辨認(rèn),這時(shí)每測(cè)試一次密碼,黑客都得仔細(xì)辨認(rèn)一下驗(yàn)證碼圖片,然后手工輸入驗(yàn)證碼文本。最多要輸入一百萬次,估計(jì)全世界沒人會(huì)愿意進(jìn)行這樣的工作。這樣驗(yàn)證碼技術(shù)就有效的抵御了這種枚舉字典測(cè)試密碼的安全攻擊。此時(shí)黑客會(huì)轉(zhuǎn)而尋找其他方法,而大量的初級(jí)黑客會(huì)放棄攻擊這個(gè)網(wǎng)站。
驗(yàn)證碼技術(shù)概念????驗(yàn)證碼技術(shù)利用了人腦和電腦之間的差別。
????大家都知道電腦和人腦是存在很大的差別的,電腦很勝任數(shù)值運(yùn)算和精確的邏輯判斷,很適合執(zhí)行那些重復(fù)又重復(fù)的簡(jiǎn)單數(shù)據(jù)處理,但圖像識(shí)別,模糊邏輯判斷,學(xué)習(xí)和創(chuàng)新能力很差。而人腦正好相反,數(shù)值運(yùn)算不行,但圖像識(shí)別卻很擅長(zhǎng)。
????在驗(yàn)證碼技術(shù)中,有一個(gè)很關(guān)鍵的過程就是需要從一個(gè)充滿隨機(jī)形狀的圖片中辨認(rèn)出驗(yàn)證碼文本,這個(gè)過程目前的電腦是難以實(shí)現(xiàn)的,而對(duì)人腦卻能相當(dāng)容易。
????采用電腦難于識(shí)別而人腦容易識(shí)別的圖片,強(qiáng)迫人腦參與安全信息驗(yàn)證過程,就是驗(yàn)證碼技術(shù)。這里包含驗(yàn)證碼文本的圖片是驗(yàn)證碼媒介。仔細(xì)觀察,我們可以知道這種驗(yàn)證碼媒介具有電腦創(chuàng)建容易識(shí)別難的特點(diǎn),因此類似的我們也可以采用合成語(yǔ)音等其他手段來作為驗(yàn)證碼媒介。例如服務(wù)器提供一個(gè)類似QQ表情的圖片,加上噪聲,然后讓用戶判斷選擇這個(gè)圖片的表情狀態(tài),是哭是笑還是流鼻血,這樣也可以當(dāng)作驗(yàn)證碼。
????由于枚舉字典安全攻擊需要大數(shù)量的嘗試猜測(cè)安全信息,其重復(fù)過程可能需要數(shù)萬甚至數(shù)億次,而驗(yàn)證碼技術(shù)強(qiáng)迫了人腦參與每一次嘗試猜測(cè)安全信息,人腦難以勝任長(zhǎng)時(shí)間高頻率的簡(jiǎn)單重復(fù)勞動(dòng),因此這就使得枚舉字典安全攻擊變得不可行,如此應(yīng)用程序成功的防御了枚舉字典安全攻擊。
ASP.NET中使用驗(yàn)證碼技術(shù)????由于驗(yàn)證碼技術(shù)中服務(wù)器程序需要?jiǎng)?chuàng)建驗(yàn)證碼圖片,里面用到了圖形編程,因此本節(jié)課程仍然是C#發(fā)現(xiàn)之旅的圖形編程系列教程。
????根據(jù)驗(yàn)證碼的原理,我們使用C#在ASP.NET中實(shí)現(xiàn)了驗(yàn)證碼的功能。
checkimage.aspx????首先根據(jù)上節(jié)課程的內(nèi)容,我們要?jiǎng)?chuàng)建一個(gè)圖片服務(wù)頁(yè)面,專門用于提供包含驗(yàn)證碼文本的圖片,為此我們建立一個(gè) checkimage.aspx 的頁(yè)面。其HTML代碼很簡(jiǎn)單,只有一行,不輸出任何內(nèi)容。在其Page_Load方法中就有創(chuàng)建驗(yàn)證碼圖片的過程。
// 創(chuàng)建一個(gè)包含隨機(jī)內(nèi)容的驗(yàn)證碼文本 System.Random rand = new Random(); int len = rand.Next(4 , 6 ); char[] chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); System.Text.StringBuilder myStr = new System.Text.StringBuilder(); for( int iCount = 0 ; iCount < len ; iCount ++ ) { ??? myStr.Append( chars[ rand.Next( chars.Length )]); } string text = myStr.ToString(); // 保存驗(yàn)證碼到 session 中以便其他模塊使用 this.Session["checkcode"] = text ; Size ImageSize = Size.Empty ; Font myFont = new Font("MS Sans Serif" , 20 ); // 計(jì)算驗(yàn)證碼圖片大小 using( Bitmap bmp = new Bitmap( 10 , 10 )) { ??? using( Graphics g = Graphics.FromImage( bmp )) ??? { ??????? SizeF size = g.MeasureString( text , myFont , 10000 ); ??????? ImageSize.Width = ( int ) size.Width + 8 ; ??????? ImageSize.Height = ( int ) size.Height + 8 ; ??? } } // 創(chuàng)建驗(yàn)證碼圖片 using( Bitmap bmp = new Bitmap( ImageSize.Width , ImageSize.Height )) { ??? // 繪制驗(yàn)證碼文本 ??? using( Graphics g = Graphics.FromImage( bmp )) ??? { ??????? g.Clear( Color.White ); ??????? using( StringFormat f = new StringFormat()) ??????? { ??????????? f.Alignment = StringAlignment.Near ; ??????????? f.LineAlignment = StringAlignment.Center ; ??????????? f.FormatFlags = StringFormatFlags.NoWrap ; ??????????? g.DrawString( ??????????????? text , ??????????????? myFont , ??????????????? Brushes.Black , ??????????????? new RectangleF( ??????????????? 0 , ??????????????? 0 , ??????????????? ImageSize.Width , ??????????????? ImageSize.Height ), ??????????????? f ); ??????? }//using ??? }//using ??? // 制造噪聲 雜點(diǎn)面積占圖片面積的 30% ??? int num = ImageSize.Width * ImageSize.Height * 30 / 100 ; ??? for( int iCount = 0 ; iCount < num ; iCount ++ ) ??? { ??????? // 在隨機(jī)的位置使用隨機(jī)的顏色設(shè)置圖片的像素 ??????? int x = rand.Next( ImageSize.Width ); ??????? int y = rand.Next( ImageSize.Height ); ??????? int r = rand.Next( 255 ); ??????? int g = rand.Next( 255 ); ??????? int b = rand.Next( 255 ); ??????? Color c = Color.FromArgb( r , g , b ); ??????? bmp.SetPixel( x , y , c ); ??? }//for ??? // 輸出圖片 ??? System.IO.MemoryStream ms = new System.IO.MemoryStream(); ??? bmp.Save( ms , System.Drawing.Imaging.ImageFormat.Png ); ??? this.Response.ContentType = "image/png"; ??? ms.WriteTo( this.Response.OutputStream ); ??? ms.Close(); }//using myFont.Dispose(); |
????首先我們使用.NET框架中隨機(jī)數(shù)生成器 Random類型來生成一個(gè)不定長(zhǎng)的包含隨機(jī)數(shù)字和英文字符的文本,這就是驗(yàn)證碼原始文本,我們將其保存在session中供以后使用。
????然后我們創(chuàng)建一個(gè)臨時(shí)圖片,并據(jù)此創(chuàng)建一個(gè)臨時(shí)的圖象繪制對(duì)象,然后調(diào)用Graphics的MeasureString函數(shù)獲得這個(gè)字符串的顯示大小。據(jù)此我們就可以計(jì)算出驗(yàn)證碼圖片的大小。
????然后我們創(chuàng)建一個(gè)位圖對(duì)象,在此基礎(chǔ)上創(chuàng)建一個(gè)圖形繪制對(duì)象,然后調(diào)用圖形繪制對(duì)象的DrawString函數(shù)將驗(yàn)證碼文本繪制在這個(gè)位圖上。
????繪制驗(yàn)證碼后我們?cè)趫D片上隨機(jī)的制造雜點(diǎn)來混淆圖片內(nèi)容。這些雜點(diǎn)的面積占圖片面積的30%,而且其位置和顏色都是隨機(jī)的。這些雜點(diǎn)能嚴(yán)重的干擾程序辨認(rèn)驗(yàn)證碼文本。但人腦在辨認(rèn)文本時(shí)能比較輕松的排除這些干擾。
????圖片生成后頁(yè)面就使用PNG格式將圖片文檔發(fā)送到客戶端。
checkimage.aspx還提供了一個(gè)靜態(tài)函數(shù)來檢測(cè)驗(yàn)證碼。
| /// <summary> /// 檢查指定的文本是否匹配驗(yàn)證碼 /// </summary> /// <param name="text">要判斷的文本</param> /// <returns>是否匹配</returns> public static bool CheckCode( string text ) { ??? string txt = System.Web.HttpContext.Current.Session["checkcode"] as string ; ??? return text == txt ; } |
????代碼很簡(jiǎn)單。就是看看參數(shù)傳進(jìn)的文本是否等于 session 中保存的驗(yàn)證碼文本。其他的頁(yè)面程序調(diào)用這個(gè)函數(shù)就可以判斷驗(yàn)證碼的正確性。
login.aspx????驗(yàn)證碼圖片服務(wù)頁(yè)面完成后,我們就可以利用這個(gè)頁(yè)面來實(shí)現(xiàn)驗(yàn)證碼技術(shù)。我們建立一個(gè)模擬系統(tǒng)登錄的頁(yè)面。
????上面放置輸入用戶名,密碼和驗(yàn)證碼的三個(gè)文本輸入框。其中驗(yàn)證碼輸入框后面放置一個(gè)圖片,圖片就來源于checkimage.aspx頁(yè)面。用戶輸入三個(gè)信息后點(diǎn)擊確定按鈕進(jìn)行登錄。則運(yùn)行該按鈕的服務(wù)器段代碼。
| private void cmdOK_Click(object sender, System.EventArgs e) { ??? string UserName = this.txtUserName.Text ; ??? string Password = this.txtPassword.Text ; ??? string CheckCode = this.txtCheckCode.Text ; ??? if( UserName == "張三" ??????? && Password == "abc" ??????? && checkimage.CheckCode( CheckCode ) ) ??? { ??????? this.lblResult.Text = "<b>登錄成功</b>"; ??????? this.RegisterStartupScript("a" , "<script>alert('登錄成功');</script>"); ??? } ??? else ??? { ??????? this.lblResult.Text = "<font color=red><b>用戶登錄信息錯(cuò)誤,請(qǐng)重新輸入</b></font>"; ??? } } |
????在該代碼中,程序獲得用戶輸入的用戶名,密碼和驗(yàn)證碼,然后判斷用戶名密碼是否正確,還調(diào)用checkimage的靜態(tài)函數(shù)CheckCode來判斷驗(yàn)證碼是否正確。只有這三個(gè)信息都正確則登錄成功,否則登錄失敗。
????在少數(shù)情況下,程序生成的驗(yàn)證碼圖片難以辨認(rèn),則需要重新提供新的驗(yàn)證碼圖片,此時(shí)我們?cè)诘卿涰?yè)面中可以雙擊這個(gè)圖片來更新驗(yàn)證碼圖片。顯示驗(yàn)證碼圖片的HTML代碼片斷為
| <img src="checkimage.aspx" ??? title='看不清楚,雙擊圖片換一張。' ??? ondblclick="this.src = 'checkimage.aspx?flag=' + Math.random() " ??? border="1"> |
????可以看到 ondblclick 事件處理中更新了圖片來源,這里使用了一個(gè)毫無意義的flag頁(yè)面參數(shù),這是保證瀏覽器不會(huì)使用本地緩存的驗(yàn)證碼圖片而是下載最新的驗(yàn)證碼圖片。
????用戶雙擊圖片后,瀏覽器重新調(diào)用checkimage.aspx頁(yè)面,于是服務(wù)器端的驗(yàn)證碼文本用了新的,而圖片內(nèi)容也隨之更新。
????由于每次嘗試登錄或更換驗(yàn)證碼圖片時(shí),正確的驗(yàn)證碼都是隨機(jī)的發(fā)生改變,毫無規(guī)律,這樣就很大的增強(qiáng)了登錄頁(yè)面的安全性。但這樣做會(huì)讓用戶登錄時(shí)需要辨認(rèn)和輸入驗(yàn)證碼,這會(huì)降低應(yīng)用程序的可用性。因此是否使用驗(yàn)證碼技術(shù)是需要多方面權(quán)衡的。
小結(jié)????在本次課程中,我們一起研究了驗(yàn)證碼技術(shù)的原理,并使用C#在ASP.NET中實(shí)現(xiàn)了簡(jiǎn)單的驗(yàn)證碼技術(shù)。驗(yàn)證碼技術(shù)是一種安全防御技術(shù),其中使用了一定的圖形編程。這樣看來圖形編程應(yīng)用是廣泛的,可以為很多其他的技術(shù)提供支持。
總結(jié)
以上是生活随笔為你收集整理的C#发现之旅第九讲 ASP.NET验证码技术的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XHTML Strict和Transit
- 下一篇: c#加粗代码_c#窗体,选中复选框,文字