[技術探討] CAPTCHA 探討

CAPTCHA

俗稱的驗證碼英文為Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA,用途為防止電腦偽裝使用者的自動程式,在CAPTCHA測試中,作為伺服器的電腦會自動生成一個問題由使用者來解答,藉此判斷使用者是否為電腦,所以驗證的問題必須有由服務端自動產生並且無法被電腦給解開的特性。

歷史CAPTCHA這個詞最早在2002年由卡內基梅隆大學的路易斯·馮·安、Manuel Blum、Nicholas J.Hopper及IBM的John Langford所提出。卡內基梅隆大學曾申請CAPTCHA一詞為註冊商標失敗。目前大多數的CAPTCHA為讓使用者輸入螢幕上所看到被扭曲變形的文字和數字,來辨識使用者是否為人類運用。

CAPTCHA的運用十分廣泛,有網站的會員註冊防止大量的機器人辦理帳號、論壇的發文與回文防止惡意的洗板或留言攻擊、訂票系統大量機器人收購等等地方,筆者個人認為網站只要是給予任何使用者自由輸入,且這些資料必須被服務端所存取的頁面都有需要使用CAPTCHA防止惡意攻擊破解。

目前最為廣泛的文數字辨別方式常常被使用影像辨識的方式破解,就算辨識成功機率可能只有10%或是更低,但是以大量的方式發送請求成功的數量也非常地可觀。

CAPTCHA實務介紹

目前有很多CAPTCHA的實作方法,包含了google的reCAPTCHA或是Captcha by BestWebSoft、BotDetect CAPTCHA等等其他公司或是私人所撰寫的提供的API或是套件,筆者實作了一個網路的套件jQuery前端驗證的排序驗證方法在ITE2 NAS網站客服表單的留言區塊提供使用者一個叫不一樣的驗證方式。

以下為Demo的畫面(P1)和原始碼

CAPTCHA

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<title>Registration Form with Draggable Capture</title>
			<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
			<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
			<script type="text/javascript" src="jquery-ui.min.js"></script>
			<style type="text/css">
				.captcha_wrap{
					border:1px solid #fff;
					-moz-border-radius:10px;
					-webkit-border-radius:10px;
					-moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5);
					-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5);
					float:left;
					height:120px;
					overflow:auto;
					width:150px;
					overflow:hidden;
					margin:0px 0px 0px 210px;
					background-color:#fff;
				}
				.captcha{
					-moz-border-radius:10px;
					-webkit-border-radius:10px;
					font-size:12px;
					color:#BBBBBB;
					text-align: center;
					border-bottom:1px solid #CCC;
					background-color:#fff;
				}
			</style>
			<script type="text/javascript">
				(
				function($){
					$.fn.shuffle = function() {
						return this.each(function(){
							var items = $(this).children();

							return (items.length)
								? $(this).html($.shuffle(items,$(this)))
							: this;
						});
					}
					$.fn.validate = function() {
						var res = false;
						this.each(function(){
							var arr = $(this).children();
							res =    ((arr[0].innerHTML=="1")&&
								(arr[1].innerHTML=="2")&&
								(arr[2].innerHTML=="3")&&
								(arr[3].innerHTML=="4")&&
								(arr[4].innerHTML=="5")&&
								(arr[5].innerHTML=="6"));
						});
						return res;
					}
					$.shuffle = function(arr,obj) {
						for(
							var j, x, i = arr.length; i;
							j = parseInt(Math.random() * i),
							x = arr[--i], arr[i] = arr[j], arr[j] = x
						);
						if(arr[0].innerHTML=="1") obj.html($.shuffle(arr,obj))
						else return arr;
					}

				})(jQuery);

				$(function() {
					$("#sortable").sortable();						//可拖曳
					$("#sortable").disableSelection();				//不可改值
					$('ul').shuffle();								//產生隨機標籤
					//檢查
					$("#formsubmit").click(function(){
						($('ul').validate()) ? alert("Yeah, you are a human!") : alert("No, you are not a human!");
					});
				});
			</script>
		</head>
		<body>
			<fieldset>
				<legend>Let's see if you are a human</legend>
				<div class="captcha_wrap">
					<div class="captcha">
			Drag to order
					</div>
					<ul id="sortable">
						<li class="captchaItem">1</li>
						<li class="captchaItem">2</li>
						<li class="captchaItem">3</li>
						<li class="captchaItem">4</li>
						<li class="captchaItem">5</li>
						<li class="captchaItem">6</li>
					</ul>
				</div>
				<a id="formsubmit" class="button">Register</a>
			</fieldset>
		</body>
	</html>

include的檔案可以換成新版的

<script src=”https://code.jquery.com/jquery-3.0.0.js”></script>

.captcha_wrap裡面可以調整驗證碼的外框,筆者把外框改成一列顯示所以設定寬高為

height:70px;

width:258px;

.captcha為上方標題的文字框,因為文字本來的設定是灰色的不是很清楚所以筆者將字體顏色改為紅色

color:#F66;

這段是驗證使用者是否輸入正確的方法(如果要增加排列個數記得修改這裡)

$.fn.validate = function() {

var res = false;

this.each(function(){

var arr = $(this).children();

res =((arr[0].innerHTML==”1″)&&

(arr[1].innerHTML==”2″)&&

(arr[2].innerHTML==”3″)&&

(arr[3].innerHTML==”4″)&&

(arr[4].innerHTML==”5″)&&

(arr[5].innerHTML==”6″));

});

return res;

}

這段是打散數字標籤的方法(亂數若剛好是正確排序會重新再取所以不會有剛好不用驗證的狀況)

$.shuffle = function(arr,obj) {

for(

var j, x, i = arr.length; i;

j = parseInt(Math.random() * i),

x = arr[–i], arr[i] = arr[j], arr[j] = x

);

if(arr[0].innerHTML==”1″) obj.html($.shuffle(arr,obj))

else return arr;

}

 

CAPTCHA

以下是個人實作的圖(P2),驗證方面筆者在submit前先檢查驗證碼

 

<button type=”submit” class=”btn btn-primary” id=”Send”>送出</button>

在click事件中設定判斷驗證碼的方法即可

$(“#Send”).bind(‘click’, function () {

if ($(‘#sortable’).validate())

return true;

else {

alert(‘驗證未輸入成功’);

return false;

}

});

後記

單純前端驗證的方法雖然快速、便利且能減少服務端的負擔,但是畢竟只是在使用者端進行驗證,很難防止直接送POST給資料庫的攻擊方式,相對不是安全的做法,目前相對安全的做法還是使用reCAPTCHA等CAPTCHA公司提供的API進行驗證。

 

參考資料:

https://zh.wikipedia.org/zh-tw/%E9%AA%8C%E8%AF%81%E7%A0%81

引用套件來源:


發佈留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料