我已经使用这个脚本很长一段时间,它在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