程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#發現之旅第九講 ASP.NET驗證碼技術

C#發現之旅第九講 ASP.NET驗證碼技術

編輯:關於C#

為了讓大家更深入的了解和使用C#,我們將開始這一系列的主題為“C#發現之旅 ”的技術講座。考慮到各位大多是進行WEB數據庫開發的,而所謂發現就是發現我們所 不熟悉的領域,因此本系列講座內容將是C#在WEB數據庫開發以外的應用。目前規劃的主要內 容是圖形開發和XML開發,並計劃編排了多個課程。在未來的C#發現之旅中,我們按照由淺入 深,循序漸進的步驟,一起探索和發現C#的其他未知的領域,更深入的理解和掌握使用C#進 行軟件開發,拓寬我們的視野,增強我們的軟件開發綜合能力。

本系列課程配套的演 示代碼。

課程說明

大家好,在上一節課程中,我們開始了解了如何在在ASP.NET中使 用圖形編程的技術。今天我們針對驗證碼技術深入的了解圖形編程在ASP.NET中的應用。

驗證碼技術是目前很多WEB程序采用的一種安全防御技術。系統在登錄的時候不但要 輸出用戶名和密碼,還要額外輸入一種隨機生成的驗證碼文本,此時用戶需要正確的輸入這 三個信息才能登錄到系統中。

由於驗證碼技術能有效的抵御某些黑客攻擊,因此得到 相當廣泛的應用,而且在一些C/S系統中也采用了這種源自WEB開發的技術。

驗證碼原 理

在現在的軟件運行環境下,安全成為大部分軟件必須考慮的問題,黑客無處不在 ,攻擊方式日益豐富,尤其是WEB系統由於其開放性更是遇到嚴峻的考驗,黑客事件層出不窮 ,造成的損失和影響也不斷變大,對此我們軟件開發人員需要對此有相當的認識並采取措施 抵御各種黑客攻擊。

枚舉字典安全攻擊

在各種黑客攻擊中,很常見的就是套 取用戶名和密碼,其中很多是采用枚舉字典的方式來不斷的測試用戶名和密碼。

比如某黑客 獲得一銀行賬號,然後打開賬號的開戶銀行的網上銀行登錄界面。分析其中的HTML代碼,發 現其頁面粗制濫造,沒有驗證碼,沒有任何安全控制,只要求輸入銀行賬號和取款密碼就可 以登錄。黑客心中大喜,馬上寫了一個程序,直接調用HTTP協議,使用程序來模擬浏覽器向 網上銀行服務器提交賬號和密碼嘗試登錄。由於取款密碼是6位阿拉伯數字,因此也就有一百 萬種組合,黑客的電腦從六個零開始測試一直到六個九,這一定會測試出真正的密碼。黑客 找到一台寬帶高速上網的電腦,運行套取取款密碼程序後就忙其他事了,假設這台電腦1秒能 測試10個密碼,於是花費10萬秒的時間肯定能找到密碼。10萬秒也就是27小時,一天多點的 時間,實際上很可能用不了那麼長的時間。黑客外頭轉了一圈回來,發現密碼已經找到了, 於是馬上登錄網上銀行撈錢,或者偽造一個銀行卡去ATM機上提取現金。也就是說黑客最多花 了一天時間即可獲得數目不可預知的非法收入。

驗證碼防御

網上銀行可以有 很多手段來抵御黑客攻擊,比如使用ActiveX控件代替標准的文本框來輸入賬號和密碼,可以 使用USB接口的密碼盤來進行數據加密和檢測,或者使用一個客戶端程序代替浏覽器來登錄網 上銀行。但這些是客戶端技術,千千萬萬的黑客可以操著各種手術刀來解剖這些技術,從根 本上說客戶端技術是不可靠的。

相對而言采用服務器端技術就比較安全了。比如發現 密碼連續錯誤3次即鎖定賬戶,1天後才能登錄;也可以使用驗證碼技術來很大程度的抵御枚 舉字典套取密碼的攻擊。

現有一個新的網上銀行,和舊網銀差不多,但采用了驗證碼 技術,用戶登錄時除了要輸入賬號和取款密碼,浏覽器還顯示一個圖片,裡面顯示了一些潦 草的字符,用戶需要辨認這些字符然後再輸入進去,浏覽器向服務器提交表單時會附加用戶 輸入的驗證碼,服務器接受表單數據後除了校驗賬號和取款密碼後,還要檢查驗證碼是否輸 入正確,若登錄信息校驗失敗,則服務器端則會提示重新登錄,而且還生成包含隨機內容的 新的驗證碼,用戶在次登錄時又得重新識別新的驗證碼了。

由於正確的驗證碼文本是 保存在服務器上的,客戶端的黑客程序不可能獲得,驗證碼的內容是隨機的,黑客程序也無 法找到規律,只能辨認從服務器端發出的包含驗證碼的圖片來獲得驗證碼。這裡就體現了電 腦和人腦的差別了,人腦在圖形識別方面遠遠超過了目前的電腦,服務器端使用一些技術生 成的書寫潦草,充滿隨機分布的雜點的圖片,人腦是可以相當容易的識別的,但目前的電腦 是難以識別的。黑客程序無法識別驗證碼,只能顯示圖片讓黑客親自辨認,這時每測試一次 密碼,黑客都得仔細辨認一下驗證碼圖片,然後手工輸入驗證碼文本。最多要輸入一百萬次 ,估計全世界沒人會願意進行這樣的工作。這樣驗證碼技術就有效的抵御了這種枚舉字典測 試密碼的安全攻擊。此時黑客會轉而尋找其他方法,而大量的初級黑客會放棄攻擊這個網站 。

驗證碼技術概念

驗證碼技術利用了人腦和電腦之間的差別。

大家 都知道電腦和人腦是存在很大的差別的,電腦很勝任數值運算和精確的邏輯判斷,很適合執 行那些重復又重復的簡單數據處理,但圖像識別,模糊邏輯判斷,學習和創新能力很差。而 人腦正好相反,數值運算不行,但圖像識別卻很擅長。

在驗證碼技術中,有一個很關 鍵的過程就是需要從一個充滿隨機形狀的圖片中辨認出驗證碼文本,這個過程目前的電腦是 難以實現的,而對人腦卻能相當容易。

采用電腦難於識別而人腦容易識別的圖片,強 迫人腦參與安全信息驗證過程,就是驗證碼技術。這裡包含驗證碼文本的圖片是驗證碼媒介 。仔細觀察,我們可以知道這種驗證碼媒介具有電腦創建容易識別難的特點,因此類似的我 們也可以采用合成語音等其他手段來作為驗證碼媒介。例如服務器提供一個類似QQ表情的圖 片,加上噪聲,然後讓用戶判斷選擇這個圖片的表情狀態,是哭是笑還是流鼻血,這樣也可 以當作驗證碼。

由於枚舉字典安全攻擊需要大數量的嘗試猜測安全信息,其重復過程 可能需要數萬甚至數億次,而驗證碼技術強迫了人腦參與每一次嘗試猜測安全信息,人腦難 以勝任長時間高頻率的簡單重復勞動,因此這就使得枚舉字典安全攻擊變得不可行,如此應 用程序成功的防御了枚舉字典安全攻擊。

ASP.NET中使用驗證碼技術

由於驗 證碼技術中服務器程序需要創建驗證碼圖片,裡面用到了圖形編程,因此本節課程仍然是C# 發現之旅的圖形編程系列教程。

根據驗證碼的原理,我們使用C#在ASP.NET中實現了 驗證碼的功能。

checkimage.aspx

首先根據上節課程的內容,我們要創建一 個圖片服務頁面,專門用於提供包含驗證碼文本的圖片,為此我們建立一個 checkimage.aspx 的頁面。其HTML代碼很簡單,只有一行,不輸出任何內容。在其Page_Load 方法中就有創建驗證碼圖片的過程。

// 創建一個包含隨機內容的驗證碼文本
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();
// 保存驗證碼到 session 中以便其他模塊使用
this.Session["checkcode"] = text ;
Size ImageSize = Size.Empty ;
Font myFont = new Font("MS Sans Serif" , 20 );
// 計算驗證 碼圖片大小
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 ;
  }
}
// 創建驗證碼圖片
using( Bitmap bmp = new Bitmap( ImageSize.Width , ImageSize.Height ))
{
  // 繪制驗證碼文本
   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
  // 制造噪聲 雜點面積占圖片面積的 30%
  int num = ImageSize.Width * ImageSize.Height * 30 / 100 ;
  for( int iCount = 0 ; iCount < num ; iCount ++ )
  {
    // 在隨機的位置使用隨機的顏色設置圖片的像素
    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 框架中隨機數生成器 Random類型來生成一個不定長的包含隨機數字和英文字符的文本,這就 是驗證碼原始文本,我們將其保存在session中供以後使用。

然後我們創建一個臨時 圖片,並據此創建一個臨時的圖象繪制對象,然後調用Graphics的MeasureString函數獲得這 個字符串的顯示大小。據此我們就可以計算出驗證碼圖片的大小。

然後我們創建一個 位圖對象,在此基礎上創建一個圖形繪制對象,然後調用圖形繪制對象的DrawString函數將 驗證碼文本繪制在這個位圖上。

繪制驗證碼後我們在圖片上隨機的制造雜點來混淆圖 片內容。這些雜點的面積占圖片面積的30%,而且其位置和顏色都是隨機的。這些雜點能嚴重 的干擾程序辨認驗證碼文本。但人腦在辨認文本時能比較輕松的排除這些干擾。

圖片 生成後頁面就使用PNG格式將圖片文檔發送到客戶端。

checkimage.aspx還提供了一個 靜態函數來檢測驗證碼。

/// <summary>
/// 檢查指定的文本是 否匹配驗證碼
/// </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 ;
}

代碼很簡單。就是看 看參數傳進的文本是否等於 session 中保存的驗證碼文本。其他的頁面程序調用這個函數就 可以判斷驗證碼的正確性。

login.aspx

驗證碼圖片服務頁面完成後,我們就 可以利用這個頁面來實現驗證碼技術。我們建立一個模擬系統登錄的頁面。

上面放置輸 入用戶名,密碼和驗證碼的三個文本輸入框。其中驗證碼輸入框後面放置一個圖片,圖片就 來源於checkimage.aspx頁面。用戶輸入三個信息後點擊確定按鈕進行登錄。則運行該按鈕的 服務器段代碼。

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>用戶登錄信息錯誤,請重 新輸入</b></font>";
  }
}

在該代碼中, 程序獲得用戶輸入的用戶名,密碼和驗證碼,然後判斷用戶名密碼是否正確,還調用 checkimage的靜態函數CheckCode來判斷驗證碼是否正確。只有這三個信息都正確則登錄成功 ,否則登錄失敗。

在少數情況下,程序生成的驗證碼圖片難以辨認,則需要重新提供 新的驗證碼圖片,此時我們在登錄頁面中可以雙擊這個圖片來更新驗證碼圖片。顯示驗證碼 圖片的HTML代碼片斷為

<img src="checkimage.aspx"
   title='看不清楚,雙擊圖片換一張。'
  ondblclick="this.src = 'checkimage.aspx?flag=' + Math.random() "
   border="1">

可以看到 ondblclick 事件處理中更新了圖片來 源,這裡使用了一個毫無意義的flag頁面參數,這是保證浏覽器不會使用本地緩存的驗證碼 圖片而是下載最新的驗證碼圖片。

用戶雙擊圖片後,浏覽器重新調用 checkimage.aspx頁面,於是服務器端的驗證碼文本用了新的,而圖片內容也隨之更新。

由於每次嘗試登錄或更換驗證碼圖片時,正確的驗證碼都是隨機的發生改變,毫無規 律,這樣就很大的增強了登錄頁面的安全性。但這樣做會讓用戶登錄時需要辨認和輸入驗證 碼,這會降低應用程序的可用性。因此是否使用驗證碼技術是需要多方面權衡的。

小 結

在本次課程中,我們一起研究了驗證碼技術的原理,並使用C#在ASP.NET中實現了 簡單的驗證碼技術。驗證碼技術是一種安全防御技術,其中使用了一定的圖形編程。這樣看 來圖形編程應用是廣泛的,可以為很多其他的技術提供支持。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved