驗證碼作為防止表單垃圾資訊普遍采用的方法,一直被廣泛使用。但是同時它造成了很不好的使用者體驗,為合法使用者的正常操作帶來不便。本文介紹了一種抛棄使用驗證碼的方法,來防止自動程式進行垃圾資訊的送出。
以前見過類似的方法,這幾天在中文版的《15天學會jQuery》上看到了原作者有關的連結(http://15daysofjquery.com/examples/contact-forms/),簡單試驗了一下效果不錯。首先說明一下整體流程,主要對原文總述部分進行了簡單翻譯:
1、當表單被載入後,我們建立一個到PHP檔案的AJAX調用;
2、該PHP檔案将取得目前時間(依靠伺服器,并不是通路者的浏覽器);
3、該PHP檔案将結合時間戳,加上一個加密的字(使用者自定義的一個字元串——譯者注),産生一個32位的“哈希”并把它作為cookie存儲到通路者的浏覽器上;
4、jQuery将接收這個從AJAX調用來的時間戳資訊,并将該哈希值或“令牌”作為表單的隐藏标簽而存儲;
5、當該表單為處理而被發送,這個時間戳的值(表單中的——譯者注)将和存儲在cookie中的32位字元“令牌”做比較;
6、如果資訊不比對,或是丢失,又或者時間戳過期,我們将終止表單處理的執行,同時這個垃圾郵件發送者将會把目标轉移到另一個簡單的獵物上(放棄我們這個目标——譯者注)。
通過上面的介紹,相信大家已經基本明白了吧。核心部分就是在頁面被載入時,采用AJAX動态建立一個特定的隐藏表單元素,該元素隻有在真正使用者通路時才會存在,對于自動化的“機器人”來說是不存在的。好了,下面我們來動手做個簡單的例子實踐一下:
這裡需要3個檔案:前端送出表單的頁面test.html,送出後的後端處理頁面test.php,以及使用者産生“令牌”的AJAX頁面do.php。(沒錯,前兩個頁面也可合并為一個)
首先當然是建立表單了:
<form method="post" name="form1" action="test.php">
<label>請輸入内容:<input type="text" name="message" /></label>
<label><input type="submit" name="submit" /></label>
</form> 接下來用javascript實作AJAX,在頁面加載完畢後從do.php擷取“令牌”(這裡使用jQuery的方法): $().ready(function(){
$.get("do.php", function(txt){
$("form[name=form1]")
.append('<input type="hidden" name="ts" value="' + txt + '">');
})
}); “令牌”是怎麼産生的呢?當然是從do.php中來的啦: <?php
//PHP5.1後可用$_SERVER['REQUEST_TIME']代替time(),更高效
$now = $_SERVER['REQUEST_TIME'];
//把時間戳與自定義字元串(我這裡用的“linvo”)拼接後進行哈希,并存入cookie
//參數0說明該cookie随浏覽器關閉而失效
setcookie('token', md5('linvo'.$now), 0);
echo $now;
?> 下面開始驗證吧: <?php
$seconds = 60 * 10; //有效時間
if(!isset($_POST['ts']) || empty($_POST['ts'])) {
die('你是機器人吧');
}
if(!isset($_COOKIE['token'])) {
die('父令牌丢失');
}
if(intval($_POST['ts']) + $seconds < $_SERVER['REQUEST_TIME']) {
die('令牌已失效');
}
if(md5('linvo'.$_POST['ts']) != $_COOKIE['token']) {
die('令牌錯誤');
}
echo '送出成功!<br />';
echo '你送出的消息是:'.$_POST['message'];
?> 到這裡,已經基本實作了防止自動化程式送出的功能。再完善一點的話,在産生“令牌”時可以加上防止緩存的代碼,如: header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check-0", false);
header("Pragma: no-cache"); 好了,測試一下效果吧。當然,驗證碼也不是毫無用處,比如可以為那些手動送出垃圾資訊的人帶來阻礙等。大家可以嘗試一下,具體情況當然還得具體對待:)