[ASP]圖片驗證碼

  • 12427
  • 0

[ASP]圖片驗證碼

前言

最近接手維護的案子裡,主要的架構是使用ASP,(ASP+ASP.NET+Java+Jsp+flash)
由於沒啥ASP的經驗,所以很多印象中很好寫的東西,在這架構跟語言底下,並不是這麼容易就可以掛上去。

最近的一個需求是,要防止機器人洗版,
所以最簡單的方式,就是加掛一個圖片驗證碼來擋script洗版的動作。
 

Survey Solution

以ASP.NET來說,點部落上已經有不少前輩有撰寫範例供大家參考,
例如: puma 的:利用ASP.NET的泛型處理常式(Handler)產生圖片驗證碼,結合IRequiresSessionState將驗證碼儲存在session裡,透過session值來驗證
還有 Dotjum大 的:Captcha 安全碼[ASP.NET] 產生驗證圖片字
這邊 puma大 的機制是使用ashx+session來做驗證, Dotjum大 的則是使用cookie。

不過,ASP沒這麼多東西好用,
所以找到了另外一篇reference,供大家參考一下,
也在這邊做個記錄,之後維護案如果還有這需求就簡單多了。
http://tw.myblog.yahoo.com/jw!_Q0jYiCTHBLxv6t9q973XG90/article?mid=29&prev=-2&next=-2&page=1&sc=1#yartcmt
 

程式碼

首先對應 puma大 的ashx,在這邊我們名字取做VerifyImage.asp,內容如下:


<%

  Call Com_CreatValidCode()
 
  Sub Com_CreatValidCode()
  Response.Expires = -9999
  Response.AddHeader "Pragma","no-cache"
  Response.AddHeader "cache-ctrol","no-cache"
  Response.ContentType = "Image/BMP"
  Randomize
  Dim i, ii, iii
  Const cAmount = 36
  Const cCode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  Dim vColorData(2)
  a=CInt(Int(Rnd * 256))
  b=CInt(Int(Rnd * 256))
  c=CInt(Int(Rnd * 256))
  vColorData(0) = ChrB(a) & ChrB(b) & ChrB(c) '隨機產生顏色
  vColorData(1) = ChrB(255) & ChrB(255) & ChrB(255) '白色
  Dim vCode(4), vCodes
  For i = 0 To 3
  vCode(i) = Int(Rnd * cAmount)  '隨機產生0~35
  vCodes = vCodes & Mid(cCode, vCode(i) + 1, 1) '取得對應字元並串接
  Next
  session("CheckCode") = vCodes  'vCodes既為產生的字串
  Dim vNumberData(36) 'vNumberData(0)對應字元0的圖像 'vNumberData(10)對應字元10的圖像
  vNumberData(0)  = "1110000111110111101111011110111101001011110100101111010010111101001011110111101111011110111110000111"
  vNumberData(1)  = "1111011111110001111111110111111111011111111101111111110111111111011111111101111111110111111100000111"
  vNumberData(2)  = "1110000111110111101111011110111111111011111111011111111011111111011111111011111111011110111100000011"
  vNumberData(3)  = "1110000111110111101111011110111111110111111100111111111101111111111011110111101111011110111110000111"
  vNumberData(4)  = "1111101111111110111111110011111110101111110110111111011011111100000011111110111111111011111111000011"
  vNumberData(5)  = "1100000011110111111111011111111101000111110011101111111110111111111011110111101111011110111110000111"
  vNumberData(6)  = "1111000111111011101111011111111101111111110100011111001110111101111011110111101111011110111110000111"
  vNumberData(7)  = "1100000011110111011111011101111111101111111110111111110111111111011111111101111111110111111111011111"
  vNumberData(8)  = "1110000111110111101111011110111101111011111000011111101101111101111011110111101111011110111110000111"
  vNumberData(9)  = "1110001111110111011111011110111101111011110111001111100010111111111011111111101111011101111110001111"
  vNumberData(10) = "1111011111111101111111101011111110101111111010111111101011111100000111110111011111011101111000100011"
  vNumberData(11) = "1000000111110111101111011110111101110111110000111111011101111101111011110111101111011110111000000111"
  vNumberData(12) = "1110000011110111101110111110111011111111101111111110111111111011111111101111101111011101111110001111"
  vNumberData(13) = "1000001111110111011111011110111101111011110111101111011110111101111011110111101111011101111000001111"
  vNumberData(14) = "1000000111110111101111011011111101101111110000111111011011111101101111110111111111011110111000000111"
  vNumberData(15) = "1000000111110111101111011011111101101111110000111111011011111101101111110111111111011111111000111111"
  vNumberData(16) = "1110000111110111011110111101111011111111101111111110111111111011100011101111011111011101111110001111"
  vNumberData(17) = "1000100011110111011111011101111101110111110000011111011101111101110111110111011111011101111000100011"
  vNumberData(18) = "1100000111111101111111110111111111011111111101111111110111111111011111111101111111110111111100000111"
  vNumberData(19) = "1110000011111110111111111011111111101111111110111111111011111111101111111110111110111011111000011111"
  vNumberData(20) = "1000100011110111011111011011111101011111110001111111010111111101101111110110111111011101111000100011"
  vNumberData(21) = "1000111111110111111111011111111101111111110111111111011111111101111111110111111111011110111000000011"
  vNumberData(22) = "1000100011110010011111001001111100100111110101011111010101111101010111110101011111010101111001010011"
  vNumberData(23) = "1000100011110011011111001101111101010111110101011111010101111101100111110110011111011001111000110111"
  vNumberData(24) = "1110001111110111011110111110111011111011101111101110111110111011111011101111101111011101111110001111"
  vNumberData(25) = "1000000111110111101111011110111101111011110000011111011111111101111111110111111111011111111000111111"
  vNumberData(26) = "1110001111110111011110111110111011111011101111101110111110111011111011101001101111011001111110001011"
  vNumberData(27) = "1000001111110111011111011101111101110111110000111111010111111101101111110110111111011101111000110011"
  vNumberData(28) = "1110000011110111101111011110111101111111111001111111111001111111111011110111101111011110111100000111"
  vNumberData(29) = "1000000011101101101111110111111111011111111101111111110111111111011111111101111111110111111110001111"
  vNumberData(30) = "1000100011110111011111011101111101110111110111011111011101111101110111110111011111011101111110001111"
  vNumberData(31) = "1000100011110111011111011101111101110111111010111111101011111110101111111010111111110111111111011111"
  vNumberData(32) = "1001010011110101011111010101111101010111110101011111001001111110101111111010111111101011111110101111"
  vNumberData(33) = "1000100011110111011111101011111110101111111101111111110111111110101111111010111111011101111000100011"
  vNumberData(34) = "1000100011110111011111011101111110101111111010111111110111111111011111111101111111110111111110001111"
  vNumberData(35) = "1100000011110111011111111101111111101111111110111111110111111111011111111011111111101110111100000011"
  '底下的程式 在產生 圖檔
  Response.BinaryWrite ChrB(66) & ChrB(77) & ChrB(230) & ChrB(4) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(54) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(40) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(10) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(1) & ChrB(0)
  Response.BinaryWrite ChrB(24) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(176) & ChrB(4) & ChrB(0) & ChrB(0) & ChrB(18) & ChrB(11) & ChrB(0) & ChrB(0) & ChrB(18) & ChrB(11) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0) & ChrB(0)
  For i = 9 To 0 Step -1 
  For ii = 0 To 3    
  For iii = 1 To 10 
  'If Rnd * 99 + 1 <3 Then   ' < 右方的數值越大 代表產生的圖越看不清楚原本的字 
 '  Response.BinaryWrite vColorData(0) '使用隨機產生的顏色
  'Else
  ' Response.BinaryWrite vColorData(Mid(vNumberData(vCode(ii)), i * 10 + iii, 1))
  'End If
  ' 0 <= vCode(X) <= 35; 91~100 .. 81~90 ...... 1~10;
  Response.BinaryWrite vColorData(Mid(vNumberData(vCode(ii)), i * 10 + iii, 1))
  Next
  Next
  Next
  End Sub  
%>

VerifyImage.asp主要的用意,是用亂數產生一組英文字母和數字,記到session裡面,接著轉成圖檔輸出。
接著client端只需要把這個圖檔輸出,掛在image底下,就可以將此亂數圖片驗證碼呈現在畫面上。
例如:


<form name="formDiscussion" method="post" action="/addDiscussion.asp" id="formDiscussion">
		<textarea name="txtDisCussion" rows="10" cols="60" id="txtDisCussion"></textarea><br/>
		請輸入圖片驗證碼:<image src="/VerifyImage.asp"/><input type="text" name="CheckCode"/>
		<input type="submit" name="ButtonSave" value="確認" id="ButtonSave" />
		<input type="button" name="ButtonCancle" value="取消" id="ButtonCancle" />								
</form>

只需要將<image>的src屬性指向VerifyImage.asp,則每次向server request此src時,都會重取一次亂數。

接著只要在form的action,這邊的例子為addDiscussion.asp,去檢查給user輸入的圖片驗證碼與剛剛的session是否吻合,即可通過驗證。
例如我們這邊request與session的名字是CheckCode


<%
	if (Request("CheckCode") <> Session("CheckCode")) then
%>
	<script language="javascript">
		alert("圖片驗證碼錯誤,請重新填寫");
		history.back();
	</script>
<%
	end if
%>

值得一提的是,
當存檔成功也要返回原畫面時,
千萬不能用js的histroy.back(),因為image的src不會重新request一次,
這樣會變成存檔成功後,圖片驗證碼還是舊的,就喪失了阻擋機器人洗版的目的。
建議可以改採用下面寫法:


<script language="javascript">
	alert("留言成功");	
	window.location.href=document.referrer;	
</script>

 

結論

如果可以,還是用ASP.NET重寫吧,親切多了…現在真不習慣直譯式的語言。


blog 與課程更新內容,請前往新站位置:http://tdd.best/