验证码生成与应用实例

 更新时间:2016年11月25日 15:25  点击:1503

验证码生成与应用实例
在写用户验证页面,如注册,登录的时候,为了加强用户登录的安全性,添加验证码验证。
验证码通过gd生成png图片,并把$randval随机数字赋给$_session['login_check_num'],在通过用户输入的$_post进行比较,来判断是否正确。达到需要实现的功能,需要修改php教程.ini文件,使php支持gd库。

<?php
//调用此页面,如果下面的式子成立,则生成验证码图片
if($_get["action"]=="verifycode")
{
    rand_create();
}
//验证码图片生成
function rand_create()
{
    //通知浏览器将要输出png图片
    header("content-type: image/png");
    //准备好随机数发生器种子 
    srand((double)microtime()*1000000);
    //准备图片的相关参数  
    $im = imagecreate(62,20);
    $black = imagecolorallocate($im, 0,0,0);  //rgb黑色标识符
    $white = imagecolorallocate($im, 255,255,255); //rgb白色标识符
    $gray = imagecolorallocate($im, 200,200,200); //rgb灰色标识符
    //开始作图    
    imagefill($im,0,0,$gray);
    while(($randval=rand()%100000)<10000);{
        $_session["login_check_num"] = $randval;
        //将四位整数验证码绘入图片 
        imagestring($im, 5, 10, 3, $randval, $black);
    }
    //加入干扰象素   
    for($i=0;$i<200;$i++){
        $randcolor = imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255));
        imagesetpixel($im, rand()%70 , rand()%30 , $randcolor);
    }
    //输出验证图片
    imagepng($im);
    //销毁图像标识符
    imagedestroy($im);
}
//检验验证码
function rand_check()
{
    if($_post["reg_rand"] == $_session["login_check_num"]){
        return true;
    }
    else{
        exit("验证码输入错误");
    }
}
?>

 

验证码,是一种区分用户是计算机和人的公共全自动程序。在captcha测试中,作为服务器的计算机会自动生成一个问题由用户来解答。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答captcha的问题,所以回答出问题的用户就可以被认为是人类。

*/
session_start();
$string = null;
$im = imagecreatetruecolor(60,25);  //创建真彩图60*25
$bg = imagecolorallocate($im,255,255,255);//白色背景
imagefill($im,0,0,$bg);填充白色
$x = 5;//
$y = 0;//文字坐标
for($i=0 ; $i&lt;4 ;$i++)
{
$char = mt_rand(0,9);
$string .=$char;
$y = mt_rand(0,10);
$ccolor = imagecolorallocate($im,mt_rand(0,230),mt_rand(0,230),mt_rand(0,230));
imagechar($im,6,$x,$y,$char,$ccolor);//填充文字
$x += mt_rand(10,15);
}
for($i=0 ;$i
{
$x1 = mt_rand(0,80);
$x2 = mt_rand(0,80);
$y1 = mt_rand(0,30);
$y2 = mt_rand(0,30);
$x2 = $x1 +mt_rand(1,5);
$y2 = $y1 +mt_rand(1,5);
$lc = imagecolorallocate($im,mt_rand(0,230),mt_rand(0,230),mt_rand(0,230));
imageline($im,$x1,$y1,$x2,$y2,$lc);//填充线条
}
$_session['code'] = md5($string);
header("content-type:image/jpeg");
imagepng($im);
imagedestroy($im);

更多详细内容请查看:http://www.111cn.net/phper/php-cy/33707.htm


当然我们也可以能过同时我们可以明知php ajax来实例验证功能。

我们只要在php教程.ini增加

disable_functions =phpinfo


php.ini里引入了一项功能disable_functions , 这个功能比较有用,可以用它禁止一些函数。比如在php.ini里加上disable_functions = passthru exec system popen 那么在执行这些函数的时候将会提示warning: system() has been disabled for security reasons,同时程序终止运行


更多详细

查找disable_functions然后用下面的替换
disable_functions =phpinfo,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source


 

注意:以下代码需要打开php教程的gd库,修改php.in文件的配置,把已经注释掉的行之前的分号取消即可:extension=php_gd2.dll。

$width = 165;
        $height = 120;
        $image = imagecreatetruecolor($width,$height);
        $bg_color = imagecolorallocate($image,255,255,255);
        $tm = imagecolorallocate($image,255,0,0);
        imagefilledrectangle($image,0,0,$width,$height,$bg_color);
        imagefill($image,0,0,$bg_color);
        /*
        //$text = random_text(5);
        $text = "ffff";
        $font = 8;
        $struft=iconv("gbk","utf-8",$text);
        $x = imagesx($image);
        $y = imagesy($image);
        $fg_color = imagecolorallocate($image,233,14,91);
        imagestring($image,$font,$x,$y,$struft,$fg_color);
        $_session['captcha'] = $text;
        */
header("content-type:image/png");
        imagepng($image);
        imagedestroy($image);

实例二

validate.php

采用了session识别,稍微改进了一下目前网络上流传的php验证码,加入杂点,数字颜色随机显示,控制4位数字显示;

<?
session_start();
//生成验证码图片
header("content-type: image/png");
$im = imagecreate(44,18);
$back = imagecolorallocate($im, 245,245,245);
imagefill($im,0,0,$back); //背景

srand((double)microtime()*1000000);
//生成4位数字
for($i=0;$i<4;$i++){
$font = imagecolorallocate($im, rand(100,255),rand(0,100),rand(100,255));
$authnum=rand(1,9);
$vcodes.=$authnum;
imagestring($im, 5, 2+$i*10, 1, $authnum, $font);
}

for($i=0;$i<100;$i++) //加入干扰象素
{
$randcolor = imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255));
imagesetpixel($im, rand()%70 , rand()%30 , $randcolor);
}
imagepng($im);
imagedestroy($im);

$_session['vcode'] = $vcodes;
?>

下面看完整实例

<?php

    @header("content-type:text/html; charset=utf-8");

    //打开session

    session_start();

?>

<html>

    <head>

       <meta http-equiv="content-type" content="text/html; charset=utf-8" />

       <title>php验证码示例</title>

    </head>

    <body>

       验证码:<br/>

       <iframe id="iimg" height="100" width=300 src="img.php" frameborder="0" ></iframe>

       <br/>

       <input type=button value="看不清,换一张" onclick="iimg.location.reload();">

       <br>

       <form action="validate.php" method="post">

           输入验证码:<input name="imgid" style="width:60">

           <input type="submit" value="确定">

       </form>

    </body>

</html>

php判断用户输入的验证码是否与系统生成的一致

<?php @header("content-type:text/html; charset=utf-8");

    //开启session

    session_start();

    //得到用户输入的验证码,并转换成大写

    $imgid_req = $_request['imgid'];

    $imgid_req = strtoupper($imgid_req);

    //验证该字符串是否注册了session变量

    if (session_is_registered($imgid_req)) {

       echo "<font color=blue >通过验证!</font>";

    } else {

       echo "<font color=red >验证错误!</font>";

    }

    //关闭session,以清除所有注册过的变量

    session_destroy();

?>

1. php教程 配置文件 php.ini 中的 magic_quotes_gpc 选项没有打开,被置为 off 2. 开发者没有对数据类型进行检查和转义

不过事实上,第二点最为重要。我认为, 对用户输入的数据类型进行检查,向 mysql教程 提交正确的数据类型,这应该是一个 web 程序员最最基本的素质。但现实中,常常有许多小白式的 web 开发者忘了这点, 从而导致后门大开。

为什么说第二点最为重要?因为如果没有第二点的保证,magic_quotes_gpc 选项,不论为 on,还是为 off,都有可能引发 sql 注入攻击。下面来看一下技术实现:

一. magic_quotes_gpc = off 时的注入攻击

magic_quotes_gpc = off 是 php 中一种非常不安全的选项。新版本的 php 已经将默认的值改为了 on。但仍有相当多的服务器的选项为 off。毕竟,再古董的服务器也是有人用的。

当magic_quotes_gpc = on 时,它会将提交的变量中所有的 '(单引号)、"(双号号)、(反斜线)、空白字符,都为在前面自动加上 。下面是 php 的官方说明:

view sourceprint?

 

magic_quotes_gpc boolean

 

sets the magic_quotes state for gpc (get/post/cookie) operations. when magic_quotes are on, all ' (single-quote), " (double quote), (backslash) and nul's are escaped with a backslash automatically


如果没有转义,即 off 情况下,就会让攻击者有机可乘。以下列测试脚本为例:

 1<?
 2if ( isset($_post["f_login"] ) )
 3{
 4  // 连接数据库教程...
 5  // ...代码略...
 6
 7  // 检查用户是否存在
 8  $t_struname = $_post["f_uname"];
 9  $t_strpwd = $_post["f_pwd"];
10  $t_strsql = "select * from tbl_users where username='$t_struname' and password = '$t_strpwd' limit 0,1";
11
12  if ( $t_hres = mysql_query($t_strsql) )
13  {
14    // 成功查询之后的处理. 略...
15  }
16}
17?>
18
19<html><head><title>sample test</title></head>
20<body>
21<form method=post action="">
22  username: <input type="text" name="f_uname" size=30><br>
23  password: <input type=text name="f_pwd" size=30><br>
24
25  <input type="submit" name="f_login" value="登录">
26</form>
27</body>

 

在这个脚本中,当用户输入正常的用户名和密码,假设值分别为 zhang3、abc123,则提交的 sql 语句如下:

1 select * from tbl_users
2 where username='zhang3' and password = 'abc123' limit 0,1

 


如果攻击者在 username 字段中输入:zhang3' or 1=1 #,在 password 输入 abc123,则提交的 sql 语句变成如下:

1 select * from tbl_users
2 where username='zhang3' or 1=1 #' and password = 'abc123' limit 0,1

 

 

 


由于 # 是 mysql中的注释符, #之后的语句不被执行,实现上这行语句就成了:

1 select * from tbl_users
2 where username='zhang3' or 1=1

 

 

 


这样攻击者就可以绕过认证了。如果攻击者知道数据库结构,那么它构建一个 union select,那就更危险了:

假设在 username 中输入:zhang3 ' or 1 =1 union select cola, colb,cold from tbl_b #

在password 输入: abc123,

则提交的 sql 语句变成:

1 select * from tbl_users
2 where username='zhang3 '
3 or 1 =1 union select cola, colb,cold from tbl_b #' and password = 'abc123' limit 0,1

 

 

 


这样就相当危险了。如果agic_quotes_gpc选项为 on,引号被转义,则上面攻击者构建的攻击语句就会变成这样,从而无法达到其目的:

1 select * from tbl_users
2 where username='zhang3' or 1=1 #'
3 and password = 'abc123'
4 limit 0,1
5
6 select * from tbl_users
7 where username='zhang3 ' or 1 =1 union select cola, colb,cold from tbl_b #'
8 and password = 'abc123' limit 0,1

 

 

 


二. magic_quotes_gpc = on 时的注入攻击

当 magic_quotes_gpc = on 时,攻击者无法对字符型的字段进行 sql 注入。这并不代表这就安全了。这时,可以通过数值型的字段进行sql注入。

在最新版的 mysql 5.x 中,已经严格了数据类型的输入,已默认关闭自动类型转换。数值型的字段,不能是引号标记的字符型。也就是说,假设 uid 是数值型的,在以前的 mysql 版本中,这样的语句是合法的:

1 insert into tbl_user set uid="1";
2 select * from tbl_user where uid="1";

 

 

 


在最新的 mysql 5.x 中,上面的语句不是合法的,必须写成这样:

1 insert into tbl_user set uid=1;
2 select * from tbl_user where uid=1;

 

 

 


这样我认为是正确的。因为作为开发者,向数据库提交正确的符合规则的数据类型,这是最基本的要求。

那么攻击者在 magic_quotes_gpc = on 时,他们怎么攻击呢?很简单,就是对数值型的字段进行 sql 注入。以下列的 php 脚本为例:

 1 <?
 2  if ( isset($_post["f_login"] ) )
 3 {
 4   // 连接数据库...
 5   // ...代码略...
 6 
 7   // 检查用户是否存在
 8    $t_struid = $_post["f_uid"];
 9   $t_strpwd = $_post["f_pwd"];
10   $t_strsql = "select * from tbl_users where uid=$t_struid and password = '$t_strpwd' limit 0,1";
11   if ( $t_hres = mysql_query($t_strsql) )
12   {
13     // 成功查询之后的处理. 略...
14   }
15
16 }
17 ?>
18 <html><head><title>sample test</title></head>
19 <body>
20 <form method=post action="">
21   user id: <input type="text" name="f_uid" size=30><br>
22
23   password: <input type=text name="f_pwd" size=30><br>
24   <input type="submit" name="f_login" value="登录">
25 </form>
26 </body>

 

 

 


上面这段脚本要求用户输入 userid 和 password 登入。一个正常的语句,用户输入 1001和abc123,提交的 sql 语句如下:

select * from tbl_users where userid=1001 and password = 'abc123' limit 0,1

 

 

 

 

如果攻击者在 userid 处,输入:1001 or 1 =1 #,则注入的sql语句如下:

select * from tbl_users where userid=1001 or 1 =1 # and password = 'abc123' limit 0,1

 

 

 

 

攻击者达到了目的。

三. 如何防止 php sql 注入攻击

如何防止 php sql 注入攻击?我认为最重要的一点,就是要对数据类型进行检查和转义。总结的几点规则如下:

php.ini 中的 display_errors 选项,应该设为 display_errors = off。这样 php 脚本出错之后,不会在 web 页面输出错误,以免让攻击者分析出有作的信息。

调用 mysql_query 等 mysql 函数时,前面应该加上 @,即 @mysql_query(...),这样 mysql 错误不会被输出。同理以免让攻击者分析出有用的信息。另外,有些程序员在做开发时,当 mysql_query出错时,习惯输出错误以及 sql 语句,例如:  1 $t_strsql = "select a from b....";
 2 if ( mysql_query($t_strsql) )
 3 {
 4   // 正确的处理
 5 }
 6 else
 7 {
 8   echo "错误! sql 语句:$t_strsql rn错误信息".mysql_query();
 9   exit;
10 }

 

 

 
 

这种做法是相当危险和愚蠢的。如果一定要这么做,最好在网站的配置文件中,设一个全局变量或定义一个宏,设一下 debug 标志:

 1 //全局配置文件中:
 2 define("debug_mode",0);    // 1: debug mode; 0: release mode
 3
 4 //调用脚本中:
 5 $t_strsql = "select a from b....";
 6 if ( mysql_query($t_strsql) )
 7 {
 8   // 正确的处理
 9 }
10 else
11 {
12   if (debug_mode)
13     echo "错误! sql 语句:$t_strsql rn错误信息".mysql_query();
14   exit;
15 }

 

 

 
 

 

对提交的 sql 语句,进行转义和类型检查。

 

四. 我写的一个安全参数获取函数

为了防止用户的错误数据和 php + mysql 注入 ,我写了一个函数 papi_getsafeparam(),用来获取安全的参数值:

 1 define("xh_param_int",0);
 2 define("xh_param_txt",1);
 3 function papi_getsafeparam($pi_strname, $pi_def = "", $pi_itype = xh_param_txt)
 4 {
 5   if ( isset($_get[$pi_strname]) )
 6     $t_val = trim($_get[$pi_strname]);
 7   else if ( isset($_post[$pi_strname]))
 8     $t_val = trim($_post[$pi_strname]);
 9   else
10     return $pi_def;
11
12   // int
13   if ( xh_param_int == $pi_itype)
14   {
15     if (is_numeric($t_val))
16       return $t_val;
17     else
18       return $pi_def;
19   }
20  
21   // string
22   $t_val = str_replace("&", "&amp;",$t_val);
23   $t_val = str_replace("<", "&lt;",$t_val);
24   $t_val = str_replace(">", "&gt;",$t_val);
25   if ( get_magic_quotes_gpc() )
26   {
27     $t_val = str_replace(""", "&quot;",$t_val);
28     $t_val = str_replace("''", "&#039;",$t_val);
29   }
30   else
31   {
32     $t_val = str_replace(""", "&quot;",$t_val);
33     $t_val = str_replace("'", "&#039;",$t_val);
34   }
35   return $t_val;
36 }

 

 

 


在这个函数中,有三个参数:

$pi_strname: 变量名
$pi_def: 默认值
$pi_itype: 数据类型。取值为 xh_param_int, xh_param_txt, 分别表示数值型和文本型。

 

 

 


如果请求是数值型,那么调用 is_numeric() 判断是否为数值。如果不是,则返回程序指定的默认值。

简单起见,对于文本串,我将用户输入的所有危险字符(包括html代码),全部转义。由于 php 函数 addslashes()存在漏洞,我用 str_replace()直接替换。get_magic_quotes_gpc() 函数是 php 的函数,用来判断 magic_quotes_gpc 选项是否打开。

刚才第二节的示例,代码可以这样调用:

 1 <?
 2 if ( isset($_post["f_login"] ) )
 3 {
 4   // 连接数据库...
 5   // ...代码略...
 6 
 7   // 检查用户是否存在
 8   $t_struid = papi_getsafeparam("f_uid", 0, xh_param_int);
 9   $t_strpwd = papi_getsafeparam("f_pwd", "", xh_param_txt);
10   $t_strsql = "select * from tbl_users where uid=$t_struid and password = '$t_strpwd' limit 0,1";
11   if ( $t_hres = mysql_query($t_strsql) )
12   {
13     // 成功查询之后的处理. 略...
14   }
15 }
16 ?>

php教程 防止注入的几种办法

其实原来就是我们需要过滤一些我们常见的关键字和符合如:

select,insert,update,delete,and,*,等等

例子:

function inject_check($sql_str) {
return eregi('select|insert|update|delete|'|/*|*|../|./|union|into|load_file
|outfile', $sql_str); // 进行过滤
}

或者是通过系统函数间的过滤特殊符号

addslashes(需要被过滤的内容)

二、 php其他地方安全设置

1、register_globals = off 设置为关闭状态

2、sql语句书写时尽量不要省略小引号和单引号

select * from table where id=2 (不规范)

select * from ·table· where ·id·=’2’ (规范)

3、正确的使用 $_post $_get $_session 等接受参数,并加以过滤

4、提高数据库教程命名技巧,对于一些重要的字段可根据程序特点命名

5、对于常用方法加以封装,避免直接暴露sql语句

 

[!--infotagslink--]

相关文章

  • PHP 验证码不显示只有一个小红叉的解决方法

    最近想自学PHP ,做了个验证码,但不知道怎么搞的,总出现一个如下图的小红叉,但验证码就是显示不出来,原因如下 未修改之前,出现如下错误; (1)修改步骤如下,原因如下,原因是apache权限没开, (2)点击打开php.int., 搜索extension=ph...2013-10-04
  • jQuery Real Person验证码插件防止表单自动提交

    本文介绍的jQuery插件有点特殊,防自动提交表单的验证工具,就是我们经常用到的验证码工具,先给大家看看效果。效果图如下: 使用说明 需要使用jQuery库文件和Real Person库文件 同时需要自定义验证码显示的CSS样式 使用实例...2015-11-08
  • JS实现随机生成验证码

    这篇文章主要为大家详细介绍了JS实现随机生成验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-06
  • php二维码生成

    本文介绍两种使用 php 生成二维码的方法。 (1)利用google生成二维码的开放接口,代码如下: /** * google api 二维码生成【QRcode可以存储最多4296个字母数字类型的任意文本,具体可以查看二维码数据格式】 * @param strin...2015-10-21
  • Java生成随机姓名、性别和年龄的实现示例

    这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
  • C#生成随机数功能示例

    这篇文章主要介绍了C#生成随机数功能,涉及C#数学运算与字符串操作相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • jQuery为动态生成的select元素添加事件的方法

    下面小编就为大家带来一篇jQuery为动态生成的select元素添加事件的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-09-01
  • Jquery插件实现点击获取验证码后60秒内禁止重新获取

    通过jquery.cookie.js插件可以快速实现“点击获取验证码后60秒内禁止重新获取(防刷新)”的功能效果图:先到官网(http://plugins.jquery.com/cookie/)下载cookie插件,放到相应文件夹,代码如下:复制代码 代码如下: <!DOCTYPE ht...2015-03-15
  • php生成唯一数字id的方法汇总

    关于生成唯一数字ID的问题,是不是需要使用rand生成一个随机数,然后去数据库查询是否有这个数呢?感觉这样的话有点费时间,有没有其他方法呢?当然不是,其实有两种方法可以解决。 1. 如果你只用php而不用数据库的话,那时间戳+随...2015-11-24
  • PHP自动生成后台导航网址的最佳方法

    经常制作开发不同的网站的后台,写过很多种不同的后台导航写法。 最终积累了这种最写法,算是最好的吧...2013-09-29
  • php实现点击可刷新验证码

    验证码类文件 CreateImg.class.php <&#63;php class ValidationCode { private $width,$height,$codenum; public $checkcode; //产生的验证码 private $checkimage; //验证码图片 private $disturbColor = ''; /...2015-11-08
  • 基于JavaScript实现验证码功能

    这篇文章主要介绍了基于JavaScript实现验证码功能的相关资料...2017-04-03
  • js生成随机数的方法实例

    js生成随机数主要用到了内置的Math对象的random()方法。用法如:Math.random()。它返回的是一个 0 ~ 1 之间的随机数。有了这么一个方法,那生成任意随机数就好理解了。比如实际中我们可能会有如下的需要: (1)生成一个 0 - 1...2015-10-21
  • JS跨浏览器解析XML应用过程详解

    这篇文章主要介绍了JS跨浏览器解析XML应用过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-10-16
  • 单击按钮发送验证码,出现倒计时的简单实例

    下面小编就为大家带来一篇单击按钮发送验证码,出现倒计时的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 代码...2017-07-06
  • Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法

    这篇文章主要介绍了Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2016-06-24
  • PHP验证码生成与验证例子

    验证码是一个现在WEB2.0中常见的一个功能了,像注册、登录又或者是留言页面,都需要注册码来验证当前操作者的合法性,我们会看到有些网站没有验证码,但那是更高级的验证了,...2016-11-25
  • PHP生成不同颜色、不同大小的tag标签函数

    复制代码 代码如下:function getTagStyle(){ $minFontSize=8; //最小字体大小,可根据需要自行更改 $maxFontSize=18; //最大字体大小,可根据需要自行更改 return 'font-size:'.($minFontSize+lcg_value()*(abs($maxFo...2013-10-04
  • 基于Pytorch版yolov5的滑块验证码破解思路详解

    这篇文章主要介绍了基于Pytorch版yolov5的滑块验证码破解思路详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-25
  • jQuery实现发送验证码控制按钮禁用功能

    最近接到新需求,需要实现一个点击发送验证码之后,按钮禁用,在5秒之后取消禁用,看似需求很简单,实现起来还真的好好动动脑筋,下面小编把jquery控制按钮禁用核心代码分享给大家,需要的朋友参考下吧...2021-07-24