利用 coldfusion 實作 CAPTCHA 驗證功能
我當然知道這樣輸入很沒效率,但是這是目前比較好的防廣告文手段。
CAPTCHA,中文常被稱為『驗證碼』,其全名為 Completely Automated Public Turing test to tell Computers and Humans Apart (全自動區分計算機和人類的圖靈測試)。媽呀,好長的名字!!!
需要詳細瞭解者可以看中文版維基的解釋或是英文版本的。
如果需要輕鬆一點的可以看看 直角兄-淺談各式各樣的網路圖形驗證碼(Captcha)
因為網路上我真的找不太到中文關於使用原生 CFML 來設計 CAPTCHA 驗證碼的文章,
真的有點感嘆,所以就自己動手寫起來以備日後的紀錄與查找。
原始碼出處:http://www.bennadel.com/blog/873-Using-CAPTCHA-In-ColdFusion-8.htm
當然英文看不輪轉的就看我這裡的吧,我已經把註解都中文化,並且稍微修改了一些。
以下程式碼需要 CF8 以上的版本, Railo3.3 測試正常執行。
其實 ColdFusion 8 以上的版本就已經支援 cfimage 的 captcha 圖片輸出,
剩下的就是如何產生圖片內容以及 驗證字串 的加/解密了。
A、頁面一開始執行時,並沒有被 Submit ,所以會由 ListToArray 產生單字陣列,
然後利用 CreateObject("java","java.util.Collections").Shuffle 擾亂陣列,
再選出前五碼作為驗證字串,這個長度可以自行決定,一般而言4~8碼都可以。
最後使用 Cfimage 的 Captcha 產生方式,difficulty可以決定是否容易識別,這個指令要注意的是
高度、寬度、字型大小與驗證字串的字元多寡,不適當的設定會讓使用者不易辨識,
或是佔用過大的畫面(版面)。
除了圖形產生以外,很重要的的是驗證字串的加密產生,這裏使用的是Encrypt指令來編碼,
使用的私鑰是 "bots-aint-sexy" 字串,將產生的加密字串captcha_check同時以隱藏方式置放在
表單裡面,加密字串的用途在於不被使用者端程式(BOT)直接識別出驗證圖片所屬的內容,
也能夠讓使用者端傳回輸入字串後進行比對是否正確。
B、當使用者輸入驗證圖片所應該表示的內容字串,並 Submit 送出表單,就會由頁面最上方
的程式碼來檢查,送回來的資訊有兩個重要的變數captcha_check和captcha,將captcha_check
用Decrypt以相同的私鑰解密以後再與captcha比對是否相同,即可得知正確與否,
此處要注意的兩點是:
一、Decrypt 必須用<cftry></cftry>包覆起來,以防止駭客利用字串編解碼漏洞進行攻擊,導致
Decrypt指令發生exception,而露出程式碼。
二、<cfif>的字串比較是沒有區分大小寫的。
另外,直角兄有提到利用中文來當驗證字串,IDEA挺好的,所以我也來改寫一下:
我把 ListToArray 改成:
再把 Cfimage 改成:
耶!成功.....
改成中文還是有需要特別注意的地方,那就是cfm檔案儲存必須使用 big5 編碼方式,
Cfimage 裡面的 fonts 必需都使用 server 上擁有的中文字型檔。
CAPTCHA,中文常被稱為『驗證碼』,其全名為 Completely Automated Public Turing test to tell Computers and Humans Apart (全自動區分計算機和人類的圖靈測試)。媽呀,好長的名字!!!
需要詳細瞭解者可以看中文版維基的解釋或是英文版本的。
如果需要輕鬆一點的可以看看 直角兄-淺談各式各樣的網路圖形驗證碼(Captcha)
因為網路上我真的找不太到中文關於使用原生 CFML 來設計 CAPTCHA 驗證碼的文章,
真的有點感嘆,所以就自己動手寫起來以備日後的紀錄與查找。
原始碼出處:http://www.bennadel.com/blog/873-Using-CAPTCHA-In-ColdFusion-8.htm
當然英文看不輪轉的就看我這裡的吧,我已經把註解都中文化,並且稍微修改了一些。
以下程式碼需要 CF8 以上的版本, Railo3.3 測試正常執行。
<cfsilent>
<!--- 設定表單參數 --->
<cfparam name="FORM.captcha" type="string" default="" />
<cfparam name="FORM.captcha_check" type="string" default="" />
<cftry>
<cfparam name="FORM.submitted" type="numeric" default="0" />
<cfcatch>
<cfset FORM.submitted = 0 />
</cfcatch>
</cftry>
<!--- 設定檢查結果標記 --->
<cfset blnIsBot = true />
<!--- 檢查表單是否 submit --->
<cfif FORM.submitted>
<!--- Decrypt 解密指令最好放在 CFTry / CFCatch 區塊內
避免有意駭客手段導致程式碼曝光,由其畫面發生exception時 --->
<cftry>
<!--- 解密表單內容 --->
<cfset strCaptcha = Decrypt(FORM.captcha_check,"bots-aint-sexy","CFMX_COMPAT","HEX") />
<!--- 檢查解密後比對使用者輸入的文字是否相同 --->
<cfif (strCaptcha EQ FORM.captcha)>
<!--- 相同的話設定標記為否 --->
<cfset blnIsBot = false />
</cfif>
<!--- 意外錯誤處理 --->
<cfcatch>
<!--- 確定標記被設定 --->
<cfset blnIsBot = true />
</cfcatch>
</cftry>
</cfif>
<!--- 頁面整理前先用java產生一組亂數 CAPTCHA 英數文字,然後交給後續處理...
建立一組有效的英文/數字陣列,但不使用0和1以免和英文字的O與I混淆 --->
<cfset arrValidChars = ListToArray(
"A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z," &
"2,3,4,5,6,7,8,9") />
<!--- 利用java擾亂陣列 --->
<cfset CreateObject("java","java.util.Collections").Shuffle(arrValidChars) />
<!--- 然後取得陣列前5碼當作是CAPTCHA文字 --->
<cfset strCaptcha = (
arrValidChars[ 1 ] &
arrValidChars[ 2 ] &
arrValidChars[ 3 ] &
arrValidChars[ 4 ] &
arrValidChars[ 5 ] ) />
<!--- 此時就可以把CAPTCHA文字當成是產生圖片的內容,因此需要在表單上放置一組可以
參考的資料,以便submit後可以比對,但是我們不想將CAPTCHA文字直接擺入表單,如此就
會被拿來破解,所以我們將產生的CAPTCHA文字進行加密 --->
<cfset FORM.captcha_check = Encrypt(strCaptcha,"bots-aint-sexy","CFMX_COMPAT","HEX") />
</cfsilent>
<cfoutput>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>ColdFusion CFImage / CAPTCHA Demo</title>
</head>
<body>
<h1>ColdFusion CFImage / CAPTCHA Demo</h1>
<form action="#CGI.script_name#" method="post">
<!--- 用來識別是否送出表單的欄位 --->
<input type="hidden" name="submitted" value="1" />
<!--- 將加密過的參考資料以不顯示方式置於表單中 --->
<input type="hidden" name="captcha_check" value="#FORM.captcha_check#" />
<p>
<!--- 輸出CAPTCHA圖片,可以由difficulty來設定混亂程度 --->
<cfimage
action="captcha"
height="45" width="200"
text="#strCaptcha#" difficulty="medium"
fonts="verdana,arial,times new roman,courier" fontsize="28" />
</p>
<label for="captcha">Please enter text in image:</label>
<input type="text" name="captcha" id="captcha" value="" />
<input type="submit" value="Submit" />
<br />
<!--- 底下用來呈現檢查的結果 --->
<cfif FORM.submitted>
<h3>Bot Validation Results</h3>
<!--- 檢查是否為bot(機器人) --->
<cfif blnIsBot>
<p>Error input!</p>
<cfelse>
<p>You are right!</p>
</cfif>
</cfif>
</form>
</body>
</html>
</cfoutput>
其實 ColdFusion 8 以上的版本就已經支援 cfimage 的 captcha 圖片輸出,
剩下的就是如何產生圖片內容以及 驗證字串 的加/解密了。
A、頁面一開始執行時,並沒有被 Submit ,所以會由 ListToArray 產生單字陣列,
然後利用 CreateObject("java","java.util.Collections").Shuffle 擾亂陣列,
再選出前五碼作為驗證字串,這個長度可以自行決定,一般而言4~8碼都可以。
最後使用 Cfimage 的 Captcha 產生方式,difficulty可以決定是否容易識別,這個指令要注意的是
高度、寬度、字型大小與驗證字串的字元多寡,不適當的設定會讓使用者不易辨識,
或是佔用過大的畫面(版面)。
除了圖形產生以外,很重要的的是驗證字串的加密產生,這裏使用的是Encrypt指令來編碼,
使用的私鑰是 "bots-aint-sexy" 字串,將產生的加密字串captcha_check同時以隱藏方式置放在
表單裡面,加密字串的用途在於不被使用者端程式(BOT)直接識別出驗證圖片所屬的內容,
也能夠讓使用者端傳回輸入字串後進行比對是否正確。
B、當使用者輸入驗證圖片所應該表示的內容字串,並 Submit 送出表單,就會由頁面最上方
的程式碼來檢查,送回來的資訊有兩個重要的變數captcha_check和captcha,將captcha_check
用Decrypt以相同的私鑰解密以後再與captcha比對是否相同,即可得知正確與否,
此處要注意的兩點是:
一、Decrypt 必須用<cftry></cftry>包覆起來,以防止駭客利用字串編解碼漏洞進行攻擊,導致
Decrypt指令發生exception,而露出程式碼。
二、<cfif>的字串比較是沒有區分大小寫的。
另外,直角兄有提到利用中文來當驗證字串,IDEA挺好的,所以我也來改寫一下:
我把 ListToArray 改成:
<cfset arrValidChars = ListToArray(
"一,二,三,四,五,六,七,八,九,零,國,兵,近,民,黨,親,愛,精,誠,你,我,他,不,謝,區,蔡,英,文,馬,九,宋,楚,魚") />
再把 Cfimage 改成:
<cfimage
action="captcha"
height="45" width="200"
text="#strCaptcha#" difficulty="medium"
fonts="細明體,新細明體,標楷體" fontsize="28" />
耶!成功.....
改成中文還是有需要特別注意的地方,那就是cfm檔案儲存必須使用 big5 編碼方式,
Cfimage 裡面的 fonts 必需都使用 server 上擁有的中文字型檔。
留言