PHP对验证码的认证过程

    这段时间在写php脚本,接触到web前端以及web安全问题比较多,这时给大家简单地谈一下我们网站验证码的验证过程及其安全问题。

    从三个方面去谈一下关于验证码的使用:验证码的生成,验证的过程,验证中注意的安全问题。

    验证码的生成,首先还是要说说验证码的作用。众所周知,验证码的存在,是为了防止一些机器,或是刷恶意留言、无限注册用户或是暴力破解账号密码。现在普通的验证码是由一个php脚本生成的,比如打开我们emlog的include/lib/文件夹,底下有个checkcode.php,这就是生成验证码的脚本。

    我们可以简单看一下它的代码:

session_start();

$randCode = '';
$chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPRSTUVWXYZ23456789';
for ( $i = 0; $i < 5; $i++ ){
	$randCode .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}

$_SESSION['code'] = strtoupper($randCode);

$img = imagecreate(70,22);
$bgColor = isset($_GET['mode']) && $_GET['mode'] == 't' ? imagecolorallocate($img,245,245,245) : imagecolorallocate($img,255,255,255);
$pixColor = imagecolorallocate($img,mt_rand(30, 180), mt_rand(10, 100), mt_rand(40, 250));

for($i = 0; $i < 5; $i++){
	$x = $i * 13 + mt_rand(0, 4) - 2;
	$y = mt_rand(0, 3);
	$text_color = imagecolorallocate($img, mt_rand(30, 180), mt_rand(10, 100), mt_rand(40, 250));
	imagechar($img, 5, $x + 5, $y + 3, $randCode[$i], $text_color);
}
for($j = 0; $j < 60; $j++){
	$x = mt_rand(0,70);
	$y = mt_rand(0,22);
	imagesetpixel($img,$x,$y,$pixColor);
}

header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);

    第一个for循环在$chars这个字符串中随机取了5个字符,这实际上就是我们的真实验证码。然后我们可以看到:$_SESSION['code'] = strtoupper($randCode); 他把我们的验证码转换成大写赋值到session里了。

    有的朋友要问,问什么赋值到SESSION里了不赋值到COOKIE里。这就说明你对他们二者关系不了解。cookie和session都作为网站临时保存客户端相关信息的一个“容器”,但是cookie是保存在客户端里的,也就是网站的访问者可以随意查看和修改cookie里的内容,那就没有验证码存在的意义了,因为用户可以直接从cookie中读到验证码,当然机器也可以。而session是保存在服务器上的内容,我生成好的验证码,用户不可能读取到。

    再看源码,后面的两个循环分别是生成彩色的带验证码的图片和在图片上加噪点。是为了加大机器识别验证码的难度。最后我们看到,header('Content-Type: image/png'); 把我们这个页面定义成为图片的格式。

    这样,我们就可以用html代码来让验证码显示出来:

<img src="checkcode.php" />
     类似这样:

    那么验证的过程就是,我们首先生成5个随机字符,保存到session里。然后把这5个字符画成一个图片给用户看,让用户识别,填写在表单里提交后和我们session里的验证码比对。

    其实就是这么简单。

    最后来说说验证码的安全性。我们emlog和wordpress其实验证码并不是很强大,我们这个简单的验证码可以写一个小脚本很容易地识别,所以并不适合比较大型的网站使用。像类似腾讯、百度这种网站的验证码很多字符能旋转、扭曲,并且背影上的干扰物更多,甚至是中文验证码。不过对于小型网站来说,普通等级的验证码足矣防范很多刷评论的机器。

    还有一点很重要,注意验证码使用过后要记住删除相应的session。否则验证码就失去了其意义,这也是我之前犯过的错误。

    为什么这么说。作为一个正常用户,我们每访问一次需要填写验证码的页面,生成验证码的脚本都会执行一次,也就说会生成一个新验证码赋值到session里,没有任何问题。但对于一个机器(或一个暴力破解密码脚本),它第一次访问需要填写验证码的页面,然后在session中得到一个验证码,它以后就不用再次访问这个页面了。直接把第一次的数据包更改并再次发送即可,于是,如果没有清除session的网站,每次的验证码都和第一次相同,也就丧失了验证码的本来作用。

    这是我们做网站需要注意的地方。希望大家在写程序的时候多注意网站的安全性,避免在网站发布后出现问题。

赞赏

喜欢这篇文章,扫码和我成为赞友!

评论

阿狗 回复

举个我遇到的例子(手机验证码):
用户没有发送手机验证码的时候,验证码字段的内容是空的
php中用mysql提取该字典内容的类型会是null
用户在浏览器中把验证码填数字0提交
php中0和null是相等的
所以就无视了手机验证码

LEAVES 回复

博主写得很透彻

杭州体检 回复

博主,你也太有才了吧;才大二就有如此成就,毕业肯定是人才。JAVA,pHP什么都不会的我,也是作为一名软件毕业生,只能去做网页设计!苦逼啊

该昵称已屏蔽 回复

该评论已屏蔽

白及 回复

^—^写得很清楚,小白我看得很happy~~~

落沐萧萧 回复

@白及:别忘点广告~

captcha