[共享][原创] 不用session的图片验证码

faisun 2006-02-22 02:16:22
用 session 实现图片验证码,浪费更多的服务器资源不说,对于客户端,也有一个弊病:如果开了一个新的窗口,因为session已更新,则在旧的窗口中按图片输入正确的字符串时,就变成错误的了.

前几天有人在 CSDN 里贴出一个双向加密的函数,顿时来了灵感,经过对这个函数进行改进,实现了不用session的图片验证码,在此与大家共享,望各位批评指正.

============= 文件: validate_image.php ================
<?php

/*
不用 session 实现的图片认证码 V1.0
作者: 暖阳
Email: faisun@sina.com
网站: http://www.softpure.com
转载请注明出处
*/

function validateCode($string,$action="ENCODE"){ //字符串加密和解密

$secret_string = 'd0nf873498**&^%$JHJK'; //绝密字符串,可以任意设定

if($string=="") return "";
if($action=="ENCODE") $crc32="@".crc32($string);
else list($string,$crc32)=split("@",$string);
$key = substr(md5($_SERVER["HTTP_USER_AGENT"].$secret_string.filemtime(str_replace('\\','/',__FILE__))),8,18);
$string = ($action=="ENCODE"?$string:base64_decode($string));
$len = strlen($key);
$code = "";
for($i=0; $i<strlen($string); $i++){
$k = $i%$len;
$code .= $string[$i]^$key[$k];
}
$code = ($action == "DECODE" ? (crc32($code)==$crc32?$code:NULL) : base64_encode($code)."$crc32");
return $code;
}


function randString($len=4){ //产生随机字符串
$chars="23456789ABCDEFGHJKLMNPRSTWXY"; //验证码可取的字符,去掉不易辨认的字符
$string="";
for($i=0;$i<$len;$i++){
srand((double)microtime()*1000000);
$rand=rand(0,strlen($chars)-1);
$string.=substr($chars,$rand,1);
}
return strtoupper($string);
}

//输出图片
if(strtolower(str_replace('\\','/',__FILE__))==strtolower(str_replace('\\','/',$_SERVER['SCRIPT_FILENAME']))){

$string = validateCode($_GET["secretCode"],"DECODE");

if(!$string) $string=' ';

Header("Content-type: image/gif");

$imageWidth = strlen($string)*20;
$imageHeight = 20;

$im = imagecreate($imageWidth,$imageHeight);

$backColor = ImageColorAllocate($im, rand(220,255),rand(220,255),rand(220,255)); //背景色

imagefilledrectangle($im, 0, 0, $imageWidth, $imageHeight, $backColor);

for($i=0;$i<100;$i++){ //画斑点
$dotColor = ImageColorAllocate($im, rand(0,255),rand(0,255),rand(0,255)); //点色
$x = rand(0,$imageWidth); $y = rand(0,$imageHeight);
imagesetpixel($im, $x, $y, $dotColor);
}

for($i=0;$i<strlen($string);$i++){ //写字
$frontColor = ImageColorAllocate($im, rand(0,120),rand(0,120),rand(0,120)); //字色
imagestring($im, 5, rand(20*$i+1,20*$i+10), rand(0,5), substr($string,$i,1),$frontColor);
}

imagepng($im);
imagedestroy($im);
exit;
}
?>


============ 应用举例,文件 demo.php =================
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>faisun@sina.com</title>
<style type="text/css">
body,td{ font-size:12px; }
</style>
</head>

<body>
<?
include("validate_image.php");

if($_REQUEST[action]=="confirm"){
if(!$_POST["secretCode"]||strtoupper($_POST[ValidateCode])!=validateCode($_POST["secretCode"],"DECODE")){
echo "验证码错误!";
exit;
}else{
echo "验证码输入正确."; //改为你其他的处理代码.

}
}else{
?>
<form name="form1" method="post" action="">
<table width="300" border="0" cellspacing="0" cellpadding="3">
<tr>
<td width="110" align="right">验证码:</td>
<td width="178">
<?
$secretCode = validateCode(randString(4));
?>
<input name="ValidateCode" type="text" id="ValidateCode" size="10">
<img src="validate_image.php?secretCode=<?=urlencode($secretCode);?>" align="absmiddle">
<input type='hidden' name='secretCode' value='<?=$secretCode;?>'>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><input name="action" type="hidden" id="action" value="confirm">
<input type="submit" name="Submit" value="确定"></td>
</tr>
</table>
</form>
<?
}
?>
</body>
</html>
...全文
487 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
faisun 2006-02-22
  • 打赏
  • 举报
回复
谢谢提示,我加了时效上去了,结帖,并新开一帖重新发过 :)
ashchen 2006-02-22
  • 打赏
  • 举报
回复
faisun(暖阳)
看来你还不知道我怎么破的
我不需要绝密字符串,只要打开你的网页,得到string,然后人工得到验证码,再去制造表单,表单上填上这两个值,提交就可以crack了
faisun 2006-02-22
  • 打赏
  • 举报
回复
-_-! 我忽略了一个认码可以反复用了
ashchen 2006-02-22
  • 打赏
  • 举报
回复
共同学习嘛,楼主的步骤稍微改进一下还是可以达到一定强度的,就是控制string和验证码的时效性
超过一段时间他们就不再对应。这段时间内破解器可以自动破解几次,但过了时间它又需要新的对应关系,所以破解难度还是很大的。这个过期时间可以再实际使用中总结。
具体怎么写就留给有心人啦,挺简单的

如果加上时效性就可以算作除了session外的另一个选择
faisun 2006-02-22
  • 打赏
  • 举报
回复
ashchen(陳輝) 在你不知道"绝密字符串"的前提下,你试过你的程序绕过了吗?
mrshelly(Shelly) 你先破了这个再说吧.
mrshelly 2006-02-22
  • 打赏
  • 举报
回复
呵呵,不知道楼主这样的 验证码 弄着有何用?????
很简单就被人破掉了。
用SESSION的目的就是防止被人破。楼主可能还没有真正理解验证码。
ashchen 2006-02-22
  • 打赏
  • 举报
回复
想法是好的,但是可以轻松破解
我们知道验证码的目的是为了防止机器自动暴力破解
我制造一个表单
<form name="form1" method="post" action="demo.php">
<table width="300" border="0" cellspacing="0" cellpadding="3">
<tr>
<td width="110" align="right">验证码:</td>
<td width="178">
<input name="ValidateCode" value="4rwe" type="text" id="ValidateCode" size="10">
<input type='hidden' name='secretCode' value='V2E2dQ==@-1032244040'>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td><input name="action" type="hidden" id="action" value="confirm">
<input type="submit" name="Submit" value="确定"></td>
</tr>
</table>
</form>

就可以轻易绕过去,因为你的string和验证码是严格对应的,我只要知道一个对应关系你就不能阻止我
Fibona 2006-02-22
  • 打赏
  • 举报
回复
学习一下

21,891

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧