提问¶
问题1:应该如何正确使用图形验证码?
问题2:应该如何正确使用短信验证码?
问题3:应该如何正确使用邮件验证码?
课程单元¶
一个图片验证码的例子
错误一:验证码为空
错误二:验证码太简单
错误三:在客户端校验验证码
错误四:验证码保存在cookie中
错误五:没有及时销毁验证码
错误六:验证码图片文件名漏洞
错误七:验证码没有跟账户绑定
1. 一个图片验证码的例子¶
下面是一个简单的图片验证码:
验证码:
<input type="text" placeholder="请输入验证码" name="code" />
<img src="code.php" />
下面是图片验证码的简单php代码:
<?php
$code = rand(1000, 9999);
$_SESSION["code"] = $code;
//下面是根据code生成图片的代码(略)
下面是检查验证码是否正确的简单php代码:
<?php
if($_GET["code"] == $_SESSION["code"]){
echo "验证码正确";
}
else{
echo "验证码不正确";
}
2. 错误一:验证码为空¶
验证码是在图片中生成并且存放进session中,因此,只要我们不请求图片,则session为空,如果我们直接使用浏览器访问提交页面,例如:xxx.php?code=,传入code为空,则满足了$_GET[“code”] == $_SESSION[“code”]的条件,成功跳过了验证码判断。
解决办法:必须判断$_SESSION[“code”]是否为空。
<?php
if($_GET["code"] == $_SESSION["code"] && $_SESSION["code"] != ""){
echo "验证码正确";
}
else{
echo "验证码不正确";
}
3. 错误二:验证码太简单¶
<?php
$code = rand(1000, 9999);
$_SESSION["code"] = $code;
4位数随机码,对于找回密码等重要场合,太过于简单,用户很容易通过反复提交、暴力破解等方式进行破解。
解决办法:对于找回密码等重要场合,验证码必须足够长、足够复杂,如果采用md5方式生成验证码,则原始字符串应该是字母加数字加特殊符号,10位以上的长度,才能确保相对安全。
4. 错误三:客户端校验验证码¶
类似如下在客户端判断验证码的方式,非常容易被表单提交欺骗攻击的方式跳过验证码校验步骤,而直接提交服务器,因此,验证码校验步骤必须在服务器端进行。
<script type="text/javascript">
function emp(){
if($("#code").val() != $("#hidCode").val()){
alert("验证码错误");
return false;
}
return true;
}
</script>
6. 错误五:未及时销毁验证码¶
对于下面的判断程序,当验证码不正确时,没有及时销毁验证码,$_SESSION[“code”]中的值会一直保持不变,导致用户可以通过反复提交的方式,试出来验证码是多少。比如对于4位数验证码,用户可以使用循环,从0000到9999逐个测试,很快就能测试出来验证码是多少。
解决方法:验证码校验错误时,必须及时销毁验证码,用户必须重新获取验证码,增加用户循环测试的难度。
<?php
if($_GET["code"] == $_SESSION["code"] && $_SESSION["code"] != ""){
echo "验证码正确";
}
else{
unset($_SESSION["code"]); //需要增加销毁验证码
echo "验证码不正确";
}
7. 错误六:验证码文件名泄漏¶
例如,对于下面这种图形验证码,很容易通过查看源代码的方式,发现验证码是多少。
解决方法:验证码图片文件名不能是有实际含义的文件名,必须是用户无法理解含义的文件名,比如code.php这种没有特别含义的文件名。
<img src="images/code/4.gif" border="0" >
<img src="images/code/4.gif" border="0" >
<img src="images/code/3.gif" border="0" >
<img src="images/code/9.gif" border="0" >
8. 错误七:验证码未绑定账户¶
例如,找回密码验证码,验证码校验成功后,用户可以修改密码。类似下面的代码,用户可以传递任意的userId,导致可以修改任意用户密码。
<?php
if($_GET["code"] == $_SESSION["code"] && $_SESSION["code"] != ""){
echo "验证码正确";
//执行修改密码操作
$sql = "update user set password = '" . $_GET["password"] . "' where userId = '" . $_GET["userId"] . "'";
mysql_query($sql);
}
else{
unset($_SESSION["code"]); //需要增加销毁验证码
echo "验证码不正确";
}
解决办法:对于修改密码等与账户相关的操作,userId等关键参数,必须与验证码相关联,而不能是用户随意输入的参数。关联方式可以用数据库、session等关联,但不能是cookie,原因同错误四,用户很容易获得和修改cookie的值,构建虚假的关联关系,从而导致关联无效。
<?php
<?php
if($_GET["code"] == $_SESSION["code"] && $_SESSION["code"] != ""){
echo "验证码正确";
//执行修改密码操作
$sql = "update user set password = '" . $_GET["password"] . "' where userId = '" . $_SESSION["userId"] . "'";
mysql_query($sql);
}
else{
unset($_SESSION["code"]); //需要增加销毁验证码
echo "验证码不正确";
}