对,就是那个由奇怪字符组成的验证码

什么是验证码?

  验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写。大名鼎鼎的图灵测试,通过一个人能答得上来,而机器不能正确回答的问题(五花八门形式的问题都有。。。),用以自动区分计算机和人。偶尔有不是通过图片,而是短信验证码来验证。

  验证码的缺点也是显而易见的,破坏了用户体验(盯着看了好几遍还是傻傻分不清楚或者验证码图片显示不出来),所以需要不断在用户体验和抵挡机器OCR(光学字符识别)之间寻找平衡点。

  * 像手机号注册,需要填写身份证号之类的手段,也都附带有类似的限制机器自动提交的目的。

为什么要用验证码?主要防范哪些方面?

  验证码作为一种抵挡机器人手段,用来阻止各种批量暴力提交行为。

  主要防范:

  •   恶意注册大量用户账号
  •   使用枚举法进行密码破解
  •   机器人发帖
  •   意识不清醒的时候误操作,比如说酒后。。。

创新用法

  除了用来反机器人程序,谷歌公司还将大数据概念发扬光大,在09年收购了验证码公司reCAPTCHA,将古籍里面不确定的字和确定的字合成成验证码图片。当大量用户识别确认确定的那个字之后,通过统计排序就能得到不确定的那个字最有可能的对应文字,从而“免费”利用了填写验证码的资源。自后又将这个技术发扬光大,把谷歌街景里不能识别的商铺和路标也放在验证码里识别。

防止OCR的方法

  当天还是蓝的时候,CAPTCHA 也就是一个干干净净的字符串图片。后来就:

  • 添加背景复杂度 - 各种噪声,什么线条啊,黑点啊,彩色斑斓,边缘放置一些干扰字符,但是不作为正式验证码。
  • 增加前景复杂度 - 让字都黏在一起,让识别程序不能切割文字,字体颜色也尽量靠近背景色,文字变形,压缩,倾斜,各种扭曲
  • 使用自己设计的手写字体
  • 算术题,微积分,生活常识,历史地理知识!!!(简直就是反学渣系统)
  • 使用动画效果,让程序分不清哪些帧是有用的
  • 特别的模式,比如说在10张人像中,跳出3张老外的图片,OMG
  • 干脆只提供音频验证码给用户
  • 是不是应该再开发一个需要简单玩游戏的验证码机制呢?哈哈

辅助视听

  当验证码太难看清(字符分割不好,变形太厉害,显示屏太烂等),用户就需要使用耳朵听的方法得到验证码。一般来说,可以在服务器端根据生成的字符串,动态合成一段MP3,传送到客户端进行播放。

简单的编程实现方法介绍

<?php

if(!isset($_SESSION)){

    session_start();

}

class captcha {

    private $width  = 60;

    private $height = 25;

    private $length = 4;

    private $code;

    private $img;

    private $ttf = '/volume1/web/captcha/simsunb.ttf';



    //初始化对象,需要传入字体文件位置

    public function __construct($ttf){

        $this->code = $this->genCode($this->length);

        $this->ttf = $ttf;

    }



    //可以自定义验证框大小,字符数量

    public function setSize($width,$height,$length){

        $this->width  = $width;

        $this->height = $height;

        $this->length = $lenght;

        $this->code = $this->genCode($length);

    }



    //产生随机字符串

    private function genCode($length){

        $pattern = '1234567890ABCDEFGHIJKLOMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

        $patternLength = strlen($pattern);

        for($i=0;$i<$length;$i++) {

            $key .= $pattern{mt_rand(0,$patternLength-1)};

        }

        return $key;

    }



    //获取随机字符串,用于传送到前端,进行验证(通常还会进一步md5加密)

    public function getCode(){

        return $this->code;

    }



    //产生验证图片,如果继承captcha类,则可以复写该函数,添加额外的噪声方法

    public function genImg($pointNum,$lineNum){

        $this->initialImg();

        $this->writeString($this->img,$this->code,$this->ttf);

        $this->writePoints($this->img,$pointNum);

        $this->writeLines($this->img,$lineNum);

    }



    //以png格式输出图片

    public function outputImg(){

        ob_clean();

        header('Content-type:image/png');

        imagepng($this->img);

    }



    //初始化验证图片背景

    private function initialImg(){

        $img=imagecreate($this->width,$this->height);

        $bgcolor=imagecolorallocate($img,240,240,240);

        $rectangelcolor=imagecolorallocate($img,150,150,150);

        imagerectangle($img,1,1,$this->width-1,$this->height-1,$rectangelcolor);

        $this->img = $img;

    }



    //写入字符串

    private function writeString($img,$code,$ttf){

        $length = strlen($code);

        for($i=0;$i<$length;$i++){

            $codecolor=imagecolorallocate($img,mt_rand(50,200),mt_rand(50,128),mt_rand(50,200));

            $angle=rand(-30,30);

            $charx=$i*(($this->width-10)/$length)+8;

            $chary=($this->height+14)/2+rand(-1,1);

            imagettftext($img,15,$angle,$charx,$chary,$codecolor,$ttf,$code[$i]);

        }

    }



    //写入噪声点

    private function writePoints($img,$pointNum){

        for($i=0;$i<$pointNum;$i++){

            $pointcolor=imagecolorallocate($img,mt_rand(0,250),mt_rand(0,250),mt_rand(0,250));

            imagesetpixel($img,mt_rand(1,$this->width-1),mt_rand(1,$this->height-1),$pointcolor);

        }

    }



    //写入噪声线条

    private function writeLines($img,$lineNum){

        for($i=0;$i<$lineNum;$i++){

            $linecolor=imagecolorallocate($img,mt_rand(0,250),mt_rand(0,250),mt_rand(0,250));

            $linex=mt_rand(1,$this->width-1);

            $liney=mt_rand(1,$this->height-1);

            imageline($img,$linex,$liney,$linex+mt_rand(0,4)-2,$liney+mt_rand(0,4)-2,$linecolor);

        }

    }

}



$verifyCode = new captcha('/volume1/web/captcha/simsunb.ttf');

$verifyCode->setSize(100,50,6);

$verifyCode->genImg(100,100);

$verifyCode->outputImg();

$_SESSION['verifyCode']=md5($verifyCode->getCode());

echo $_SESSION['verifyCode'];



?>

调用页面(js验证部分就不写在这里了,方法就是拿SESSION的verifyCode和用户的字符进行md5加密校对就行了,这里需要提一下的就是,有些人会只在前端做校验,这其实只能算作预校验,所谓防君子不防小人,必须要在后端提交的时候做二次校验,否则暴力提交可以轻松绕过JS的预校验):

<img src="/captcha/index.php" />

哈哈,还不错吧,有兴趣的可以再把图像做的复杂,但是会被群众扔番茄的哟!

 

当然,很多框架其实是提供了验证码辅助函数的,不需要自己去写相关的代码,比如说CI框架:

$this->load->helper('captcha');



$vals = array(

    'word' => 'Random word',

    'img_path' => './captcha/',

    'img_url' => 'http://example.com/captcha/',

    'font_path' => './path/to/fonts/texb.ttf',

    'img_width' => '150',

    'img_height' => 30,

    'expiration' => 7200

    );



$cap = create_captcha($vals);

echo $cap['image'];

是不是很简单!

你可能感兴趣的:(验证码)