最近、システムは広告マシンからのスパム攻撃に頻繁に遭遇します。多くの人が思いつく方法は、認証コードの難易度を上げたり、質疑応答をしたりして防ぐことです。しかし、これは広告マシンの利用を妨げる一方で、通常のユーザーの使用と経験に大きな困難を引き起こします。ここでは、スマートな検証コードのアイデアを紹介します。
つまり、短期間で認証コードの使用に成功すると、認証コードの使用頻度記録が +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 < 0) $num = 0; $len += $num; } if($len > 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 < $len; $i++) $str .= substr($Ccharlist, mt_rand(0, $max) * 3, 3); }else { $max = strlen($charlist) - 1; for($i = 0; $i < $len; $i++) $str .= $charlist[mt_rand(0, $max)]; } return $str; }
//在验证码检查确认正确之后,进行如下操作$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 < 0) $num = 0; $s = array( '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]'"); } }
まだコードを検証しておらず、注意深く見ていません、しかし、最初にアイデアと共有の精神を賞賛しなければなりません...
共有してくれてありがとう。保存されました。
良いアイデアですね。学んだ。 。
私は PHP を初めて使用するため、コードをよく理解できません。私の質問は、この方法でデータベースを使用すると、サーバーにどのくらいの負荷がかかるかということです。
それは良いアイデアで、Baidu と Sina Weibo は現在これを実行しています。
ただし、実際には、この値を mysql に記録することはできません。そうでない場合は、データベースのチェックと書き込み操作だけで十分です。
インメモリ データベースのハッシュ テーブルを使用してこの値を保存できます。ハッシュ キーは session_id にすることができます。
梨が少し大きい気がします。配列に格納する必要があるのでしょうか?
それは良いアイデアで、Baidu と Sina Weibo は現在これを実行しています。
ただし、実際には、この値を mysql に記録することはできません。そうでない場合は、データベースのチェックと書き込み操作だけで十分です。
インメモリ データベースのハッシュ テーブルを使用してこの値を保存できます。ハッシュ キーは session_id にすることができます。
nインメモリデータベースとは何ですか? ?記憶に留めておくだけですよね? ?
良いアイデアですね。 ~!
アイデアは良いので集めましたが、実装するのはそれほど簡単ではありません。良いアイデアですね、ありがとう。
これを聞くと、Tieba の確認コードを思い出します。