我已經使用這個腳本很長一段時間,它在99%完美的作品。用戶很容易和清楚,我想繼續使用它。這個PHP驗證碼腳本有什麼問題?
但是,偶爾一個稀疏的用戶告訴我,系統不接受他的驗證碼(錯誤的代碼),而數字是正確的。每次我瀏覽他們的cookies設置,清除緩存等,但在這些情況下似乎沒有任何工作。
因此,我的問題是,這個腳本的代碼是否有任何理由可以解釋特殊情況下的故障?
session_start();
$randomnr = rand(1000, 9999);
$_SESSION['randomnr2'] = md5($randomnr);
$im = imagecreatetruecolor(100, 28);
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0,0,0);
imagefilledrectangle($im, 0, 0, 200, 35, $black);
$font = '/img/captcha/font.ttf';
imagettftext($im, 30, 0, 10, 40, $grey, $font, $randomnr);
imagettftext($im, 20, 3, 18, 25, $white, $font, $randomnr);
// Prevent caching
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past3
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header ("Content-type: image/gif");
imagegif($im);
imagedestroy($im);
在我的表單中,我將此腳本作爲驗證碼圖像的來源。發送表格後,驗證碼檢查是這樣的:
if(md5($_POST['norobot']) != $_SESSION['randomnr2']) {
echo 'Wrong captcha!';
}
請注意session_start();
被稱爲表單頁面和表單的結果頁面上。
如果有人能夠在本腳本中找出潛在的錯誤原因,我將不勝感激!
P.S .:我意識到驗證碼腳本的缺點。我知道某些機器人仍然可以讀出它們。我不希望使用Recaptcha,因爲這對我的用戶來說太困難了(不同的語言+很多年齡的用戶)。我也意識到md5很容易解密的事實。
編輯編輯編輯編輯編輯編輯編輯編輯編輯編輯編輯編輯編輯編輯
繼烏戈·梅達的言論,我一直在做一些實驗。這是我所創建(簡化爲您提供方便):
形式
// Insert a random number of four digits into database, along with current time
$query = 'INSERT INTO captcha (number, created_date, posted) VALUES ("'.rand(1000, 9999).'", NOW(),0)';
$result = mysql_query($query);
// Retrieve the id of the inserted number
$captcha_uid = mysql_insert_id();
$output .= '<label for="norobot"> Enter spam protection code';
// Send id to captcha script
$output .= '<img src="/img/captcha/captcha.php?number='.$captcha_uid.'" />';
// Hidden field with id
$output .= '<input type="hidden" name="captcha_uid" value="'.$captcha_uid.'" />';
$output .= '<input type="text" name="norobot" class="norobot" id="norobot" maxlength="4" required />';
$output .= '</label>';
echo $output;
的驗證碼腳本
$font = '/img/captcha/font.ttf';
connect();
// Find the number associated to the captcha id
$query = 'SELECT number FROM captcha WHERE uid = "'.mysql_real_escape_string($_GET['number']).'" LIMIT 1';
$result = mysql_query($query) or trigger_error(__FUNCTION__.'<hr />'.mysql_error().'<hr />'.$query);
if (mysql_num_rows($result) != 0){
while($row = mysql_fetch_assoc($result)){
$number = $row['number'];
}
}
disconnect();
$im = imagecreatetruecolor(100, 28);
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0,0,0);
imagefilledrectangle($im, 0, 0, 200, 35, $black);
imagettftext($im, 30, 0, 10, 40, $grey, $font, $number);
imagettftext($im, 20, 3, 18, 25, $white, $font, $number);
// Generate the image from the number retrieved out of database
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past3
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header ("Content-type: image/gif");
imagegif($im);
imagedestroy($im);
形式
function get_captcha_number($captcha_uid) {
$query = 'SELECT number FROM captcha WHERE uid = "'.mysql_real_escape_string($captcha_uid).'" LIMIT 1';
$result = mysql_query($query);
if (mysql_num_rows($result) != 0){
while($row = mysql_fetch_assoc($result)){
return $row['number'];
}
}
// Here I would later also enter the DELETE QUERY mentioned above...
}
if($_POST['norobot'] != get_captcha_number($_POST['captcha_uid'])) {
echo 'Captcha error'
exit;
}
這一結果工作得很好,非常感謝這個解決方案。
但是,我在這裏看到一些潛在的缺點。我注意到至少4個查詢,並且對於我們正在做的事情感覺有點資源密集。另外,當用戶多次重新加載同一頁面(只是做一個混蛋)時,數據庫會很快填滿。當然這一切都會在下一次提交表格時被刪除,但是,你能否跟我一起去看看這個可能的選擇?
我知道一般應該不加密/解密。然而,由於驗證碼本質上是有缺陷的(因爲機器人的圖像讀取),我們難道不能通過加密和解密發送到captcha.php
腳本的參數來簡化過程嗎?如果
我們這樣做(以下the encrypt/decrypt instructions of Alix Axel):
1)加密的隨機四位字符像這樣:
$key = 'encryption-password-only-present-within-the-application';
$string = rand(1000,9999);
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
2)用參數發送加密號碼的圖像腳本和它存儲在一個隱藏字段
<img src="/img/captcha.php?number="'.$encrypted.'" />
<input type="hidden" name="encrypted_number" value="'.$encrypted.'" />
3)解密的數目(這是經由_GET $)驗證碼腳本中發送,並且產生從它的圖像
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
4)解密上形式的數量再次提交來比較用戶輸入 $解密= RTRIM(mcrypt_decrypt(MCRYPT_RIJNDAEL_256,MD5($鍵),BASE64_DECODE($加密),MCRYPT_MODE_CBC,MD5(MD5($鍵))),「\ 0」);
if($ _ POST ['norobot']!= $ decrypted){ echo'驗證碼錯誤!'; 退出; }
一致認爲,這有點「安全通過默默無聞」,但它似乎提供了一些基本的安全性,並保持相當簡單。或者這種加密/解密操作本身是否過於耗費資源?
有沒有人對此有任何評論?
確定另一個加工過程不破壞會話? – Leri 2012-07-05 09:45:12
好評。我很確定,因爲在99%的情況下,它能夠完美地工作(並且它始終是相同的過程)。 – maartenmachiels 2012-07-05 09:46:20
問題是否可以在訪客計算機上始終如一地重現問題,即您是否清理餅乾和所有事情,它仍然會發生? – bisko 2012-07-05 09:46:58