比较全面的php session验证码与防识别

本文探讨了验证码开发过程中常见的三个误区,并提出了有效防止被破解的技术手段,包括使用背景干扰线、矢量变形及字符粘连等方法。此外,还介绍了PHP实现验证码生成的具体代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

验证码开发过程中的 3 个误区:

  • 1、  背景干扰:干扰线、干扰点、干扰图,基本没有,程序很容易通过高亮度调节去除掉。
  • 2、  字符旋转:破解机器人通过数次学习、旋转之后,能够得到 90% 以上的正确识别率,采用常规字体,能够得到接近 100% 的识别。
  • 3、  随机间距:基本没用,采用提取高亮度之后,采用图片切割的方法,很容易就将随机间距消灭掉。

防止被破解:

  • 1、  背景干扰线尽量能够干扰到字符,采用和字符相同的颜色,能够破坏高亮度反差色提取法对字符的学习。 QQ 有采用。
  • 2、  矢量变形:想 GoogleMsYahoo 都采用了这种变态的方法,这种将字符进行扭曲变形,基本上机器识别率为零,因为没有相对应的固定形状。 损失是用户也不一定认得。需要验证码图片有一些大才行。
  • 3、  字符粘连,可以破坏掉字符切割法分割字符, Google 也有用到这个, QQ 也有采用。
  • 4、  中文验证码,中文验证码的识别难度比较大,但是现在逐渐的也慢慢被学习并且破解。(香港,台湾是用繁体)
  • 5、  字符旋转:需要和字符粘连在一起才能够起作用,他们一起,验证码几乎不具备机器破解可能性。 加随机背景图片、随机字体、稍微旋转字母或数字,位置不固定,稍微扭曲

注意:下载空心字体

字体.ttf的当$mode=7的该字体必须支持中文,否则出现乱码。

在服务端做验证时取session存储的验证字符与用户提交的字符进行比较,相同则通过验证。

<?php
/**
 *  带格式生成不重复的随机字符,支持批量生成
 *  字符格式:# 表示数字 * 表示字母和数字 @表示字母 ? 表示特殊字符
 *
 * @param string $format 字符格式: 2017@@@@####*
 * @param int $number 生成数量
 * @param array $exceptArray 排除的生成字符列表
 *
 * @return string | array
 */
public static function buildFormatRand($format, $number = 1, $exceptArray = [])
{
    $randList = array();
    $length = strlen($format);
    for ($j = 0; $j < $number; ++$j) {
        $randString = '';
        for ($i = 0; $i < $length; ++$i) {
            $char = substr($format, $i, 1);
            switch ($char) {
                case "*": //字母和数字混合
                    $randString .= self::random(1, 'FULL');
                    break;
                case "#": //数字
                    $randString .= self::random(1, "NUM");
                    break;
                case "@": //大写字母
                    $randString .= self::random(1, "ENGLISH");
                    break;
                case "?": //特殊字符
                    $randString .= self::random(1, "CHAR");
                    break;
                default: //其他格式均不转换
                    $randString .= $char;
                    break;
            }
        }
        if (!in_array($randString, $randList)) {
            if (count($exceptArray)) {
                if (!in_array($randString, $exceptArray)) {
                    $randList[] = $randString;
                } else {
                    --$j;
                }
            } else {
                $randList[] = $randString;
            }
        } else {
            --$j;
        }
    }

    return 1 == $number ? $randString : $randList;
}

function random($type, $length = 16)
{
    //字母
    $rulemapStr = 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
    //数字
    $rulemapNum = '123456789';
    //特殊字符
    $specialCharSet = '!@#$%^&*()_+-=[]{}|;:,.<>?';
    $string = '';
    for ($i = 0; $i < $length; ++$i) {
        switch ($type) {
            case 'ENGLISH':
                $rand = mt_rand(0, (strlen($rulemapStr) - 1));
                $string .= $rulemapStr[$rand];
                break;
            case 'CHINESE':
                $str[$i] = chr(mt_rand(176, 215)) . chr(mt_rand(161, 249));
                $str[$i] = iconv('GB2312', 'UTF-8', $str[$i]); //imagettftext是utf-8的,所以先转换下
                $string .= $str[$i];
                break;
            case 'NUM':
                $rand = mt_rand(0, (strlen($rulemapNum) - 1));
                $string .= $rulemapNum[$rand];
                break;
            case 'CHAR':
                $rand = mt_rand(0, (strlen($specialCharSet) - 1));
                $string .= $specialCharSet[$rand];
                break;
            case 'FULL':
                $fullstr = $rulemapStr . $rulemapNum;
                $rand = mt_rand(0, (strlen($fullstr) - 1));
                $string .= $fullstr[$rand];
                break;
        }
    }

    return $string;
}

//建立验证图片
function createAuthNumImg($randStr, $fontName, $imgW = 100, $imgH = 40)
{
    header('content-type: image/png');
    $image = imagecreate($imgW, $imgH);
    $fontSize = 20; //字号
    //$green = imagecolorallocate($image,0x6b,0xc1,0x46);
    $gray = imagecolorallocate($image, 228, 228, 228); //灰色
    $red = imagecolorallocate($image, 255, 102, 204); //粉色
    $blue = imagecolorallocate($image, 0x53, 0x68, 0xBD);
    $colors = [$red, $gray, $blue];

    $color_b = imagecolorallocate($image, 0, 0, 0); //黑色
    for ($i = 0; $i < 1000; ++$i) { //绘背景干扰点
        imagesetpixel($image, mt_rand(0, $imgW), mt_rand(0, $imgH), $colors[rand(0, count($colors) - 1)]);
    }
    imagerectangle($image, 0, 0, $imgW - 1, $imgH - 1, $color_b); //绘制边框
    imagettftext($image, $fontSize, 5, 3, 25, $color_b, $fontName, $randStr); ///将验证字符绘入图片 字符旋转
    for ($i = 0; $i < 2; ++$i) { //绘背景干扰线
        imageline($image, mt_rand(0, 5), mt_rand(6, 18), mt_rand(65, $imgW), mt_rand(6, $imgH), $color_b); //一条干扰线
    }
    imagepng($image);
    imagedestroy($image);
}

session_start();
$verifyCode = random('english', 5);
$_SESSION['VERIFY_CODE'] = $verifyCode;
createAuthNumImg($verifyCode, 'font.ttf', 75, 30); //字体存放路径,如果你没有文件就去C:\WINDOWS\Fonts文件中找一个吧。

/* 问答模式
 * $a=GetCode(2,1);
 * $b=GetCode(1,1);
 * $passPort = $a."+".$b."=?";
 * $verifyCode = $a+$b;
 * $_SESSION ['VERIFY_CODE'] = $verifyCode ;
 * createAuthNumImg ( $passPort, "font.ttf", 75, 30);
 */

中文占两个字符长度,需要控制验证码图片的长度,一个中文位置相当于2个非中文

<?php echo strlen('中'); echo strlen('ad');?>

为了避免机器人的破解,验证码的视觉效果越来越差,随之很多网站就加了“看不清?请刷新”之类的功能,当然也不是简简单单的页面刷新,是只刷新验证码部分,用户从而得到一个新的验证码。在网上看了些别人写的方法,下面总结两种。
第一种比较简单,运用一下onclick即可,直接点击验证码的图片就可以刷新,不过最好在验证码后面说明一下,提示有这个功能。

<img src="validimg.jsp" alt="看不清?请刷新" width="50" height="20" onclick="this.src=this.src+'?'+Math.random()" />

第二种则是用JavaScript的方法:

<img src="validimg.jsp" width="50" height="20" > <a href="JavaScript:reloadImage("validimg.jsp" );">刷新</a>
<script language="JavaScript">
function reloadImage(url){
document.formName.img1.src = url+Math.random();
}
</script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值