欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

防垃圾信息灌水的智能验证码

程序员文章站 2022-06-03 10:51:24
...
最近系统经常遇到广告机发的垃圾信息攻击。很多人想到的方法是增强验证码的难度,或者做一些问答来防止。但是这样在防止广告机的同时,对正常用户的使用和体验也造成很大困难。这里提供一个智能验证码的思路。

即:在短时间内成功使用验证码后,验证码使用频率记录+1。短时间内下次生成时,将自动增加长度和难度。终极变态验证码就是扭曲的中文即可。

大致代码如下:
建立一个c_iphistory数据表,用来记录验证码使用频率。
CREATE TABLE IF NOT EXISTS `c_iphistory` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `ip` varchar(255) NOT NULL,  `num` int(11) NOT NULL,  `lastdateline` int(11) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `ip` (`ip`)) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='使用验证码的ip对应次数';


生成验证码部分:
$freq = 60;//定义洪水攻击的频率	//检查是否已存储	$tmp = db::r("select * from c_iphistory where ip='$_G[ip]'");	$len = 2;	$type = 0;	if($tmp && $tmp['num'] > 0) {		$num = $tmp['num'];		$timeout = TS - $tmp['lastdateline'];		$num -= floor($timeout / $freq);//洪水指数降多少级		if($num  3){//倍增难度,长度2-5位		$type = floor($len / 4);		if($type > 8) {			$type = 8;			$len -= 34;		}else{			$len   = $len % 4;			$len += 2;		}	}else{		$len += 2;	}	$secode = s::rrand($len, $type);//下面就用$secode生成图片并记录到验证码库中以备验证即可。//************************函数部分****************************//	/**	 *	随机数 @zairwolf	 *	 */	function rrand($len, $type = 7) {//1 - Number //2 - Lower Char //4 - Upper Char //8 - Chinese		mt_srand((double)microtime() * 1000000);		switch($type) {			case 0:				$charlist = '012';				break;			case 1:				$charlist = '0123456789';				break;			case 2:				$charlist = 'abcdefghijklmnopqrstuvwxyz';				break;			case 3:				$charlist = '0123456789abcdefghijklmnopqrstuvwxyz';				break;			case 4:				$charlist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';				break;			case 5:				$charlist = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';				break;			case 6:				$charlist = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';				break;			case 7:				$charlist = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';				break;			case 8://使用中文				global $Ccharlist;				if(!$Ccharlist) $Ccharlist = file_get_contents("lib/disturbTxt.lib");				break;		}		$str = '';		if($type == 8) {			$max = strlen($Ccharlist) / 3-1;			for($i = 0; $i   

验证码验证部分
//在验证码检查确认正确之后,进行如下操作$freq = 60;//定义洪水攻击的频率	//检查是否已存储	$tmp = db::r("select * from c_iphistory where ip='$ip'");	if(!$tmp) {		$s = array(			'ip'	=> $ip,			'num'	=> 1,			'lastdateline'	=> TS,		);		db::i("insert into c_iphistory set ".sqlcol($s));	}else{//更新洪水攻击记录		$timeout = TS - $tmp['lastdateline'];		if($timeout > $freq){//超过1分之前发的,已有记录--			$num = $tmp['num'] - 1;			if($num  $num,				'lastdateline'	=> TS,			);			db::q("update c_iphistory set ".sqlcol($s)." where id='$tmp[id]'");		}else{			$num = $tmp['num'] + 1;			$s = array(				'num'	=> $num,				'lastdateline'	=> TS,			);			db::q("update c_iphistory set ".sqlcol($s)." where id='$tmp[id]'");		}	}


思路供参考。TS为time()。其它几个地方,估计大家都能看懂。

回复讨论(解决方案)

本帖最后由 PhpNewnew 于 2013-02-06 14:31:09 编辑

暂时没验证代码 也没仔细看 不过思路和分享的精神要先表扬...

感谢分享。收藏了。

思路不错。 学习了。。

刚接触PHP,代码看不太懂。我的疑问是:这样使用数据库,对服务器会造成多大的压力?

想法不错,而且现在百度、新浪微博都是这么做的。

不过实际中可不能把这个值记录在mysql中,否则光这个查库和写库操作就够受的了。
可以在内存数据库中使用hash表来存储这个值,hash key可以用session_id。

感觉这样鸭梨有点大。 难道用数组存储?

想法不错,而且现在百度、新浪微博都是这么做的。

不过实际中可不能把这个值记录在mysql中,否则光这个查库和写库操作就够受的了。
可以在内存数据库中使用hash表来存储这个值,hash key可以用session_id。

n内存数据库是啥玩意儿?? 就是放在内存是不是??

好想法。~!

思路不错,收藏了,实现起来还不是那么容易说。思路不错,谢谢了。

这让我想起贴吧的那些验证码。