没用的验证码

我们常常在提交页面设置验证码防止重复提交,但有些时候设置了验证码不一定有用,看看下面的例子:

实现用户注册的功能,需要提交以下字段:username,password,regCode,注册成功后跳转到登录页面,接受页面进行如下处理:

if($_POST['regCode'] != $_SESSION['regCode']) {
    msg('验证码不一致');
}
$username = $_POST['username'];
$password = $_POST['password'];
if(! check_username($username)) {
    msg('用户名不合法');
}
if(! check_password($password))) {
    msg('密码不合法');
}
if(check_user_exists($username)) {
    msg('用户名已被占用');
}
if(! $this->user_model->save(array(
    'username' => $username,
    'password' => $password,
))) {
    msg('注册失败');
}
header("Location:login.php");

可以看到对用户名、密码都做了校验,且设置了验证码,那是不是就没问题了呢?可以看到服务端只做了验证码校验,但在使用完验证码后并未删掉验证码,这样在下次请求中验证码是否可以重复使用呢? 我们知道验证码通常情况下存储在SESSION中,只要SESSION中验证码不被删掉而客户端请求的CookieID相同,服务端会认为是同一个用户,根据同一个CookieID想必服务端还可以拿到验证码再次使用。 我们可以这个动作用程序来模拟,并尝试多次执行:

$cookie = 'PHPSESSID=pgfac511q271k5vvije46kf634';
$post_data = array(
    'username' => 'pp'.time(),
    'password' => time(),
    'regCode' => 'dksi',
);
$ch = curl_init("http://localhost/regist.php");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch,CURLOPT_HTTPHEADER, array("Cookie: ".$cookie));
$rs = curl_exec($ch);
if(curl_errno($ch)) {
    throw new Exception('Curl Error:'.curl_error($ch));
}
curl_close($ch);
var_dump($rs);

我们只需要从浏览器上取到产生的cookie内容和显示的验证码即可,而这些通过ff或者chrome很容易就可以拿到。多次执行之后会发现数据库插入了多条记录,也就是验证码没有起到防刷的目的。同样,也可以在提交页面的时候尝试直接F5刷新,上面的逻辑则会提示用户名已被占用。

该问题产生的根本原因就是验证码使用一次之后还可以再次使用,所以解决也很简单,只需要在注册成功之后清掉验证码的值即可,再次请求时服务端session里已经没有该值了,验证码就校验不通过了。

这样的问题本属于很小的问题,但是在系统中不经意就发生了,不要让验证码变得毫无意义,等刷了几百万用户后才后知后觉^_^

-- EOF --
发表于: 2014-03-11 13:45
标签: 随笔 吐槽