PHP對驗證碼的認證過程文章重點為告訴各位如何防止機器注冊這個問題了,下面我們一起來看看例子,希望對各位有幫助.
這段時間在寫php腳本,接觸到web前端以及web安全問題比較多,這時給大家簡單地談一下我們網站驗證碼的驗證過程及其安全問題。
從三個方面去談一下關于驗證碼的使用:驗證碼的生成,驗證的過程,驗證中注意的安全問題。
驗證碼的生成,首先還是要說說驗證碼的作用。眾所周知,驗證碼的存在,是為了防止一些機器,或是刷惡意留言、無限注冊用戶或是暴力破解賬號密碼。現在普通的驗證碼是由一個php腳本生成的,比如打開我們emlog的include/lib/文件夾,底下有個checkcode.php,這就是生成驗證碼的腳本。
我們可以簡單看一下它的代碼:
- session_start();
- $randCode = '';
- $chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPRSTUVWXYZ23456789';
- for ( $i = 0; $i < 5; $i++ ){
- $randCode .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
- }
- $_SESSION['code'] = strtoupper($randCode);
- $img = imagecreate(70,22);
- $bgColor = isset($_GET['mode']) && $_GET['mode'] == 't' ? imagecolorallocate($img,245,245,245) : imagecolorallocate($img,255,255,255);
- $pixColor = imagecolorallocate($img,mt_rand(30, 180), mt_rand(10, 100), mt_rand(40, 250));
- for($i = 0; $i < 5; $i++){
- $x = $i * 13 + mt_rand(0, 4) - 2;
- $y = mt_rand(0, 3);
- $text_color = imagecolorallocate($img, mt_rand(30, 180), mt_rand(10, 100), mt_rand(40, 250));
- imagechar($img, 5, $x + 5, $y + 3, $randCode[$i], $text_color);
- } //Vevb.com
- for($j = 0; $j < 60; $j++){
- $x = mt_rand(0,70);
- $y = mt_rand(0,22);
- imagesetpixel($img,$x,$y,$pixColor);
- }
- header('Content-Type: image/png');
- imagepng($img);
- imagedestroy($img);
第一個for循環在$chars這個字符串中隨機取了5個字符,這實際上就是我們的真實驗證碼。然后我們可以看到:$_SESSION['code'] = strtoupper($randCode); 他把我們的驗證碼轉換成大寫賦值到session里了。
有的朋友要問,問什么賦值到SESSION里了不賦值到COOKIE里。這就說明你對他們二者關系不了解。cookie和session都作為網站臨時保存客戶端相關信息的一個“容器”,但是cookie是保存在客戶端里的,也就是網站的訪問者可以隨意查看和修改cookie里的內容,那就沒有驗證碼存在的意義了,因為用戶可以直接從cookie中讀到驗證碼,當然機器也可以。而session是保存在服務器上的內容,我生成好的驗證碼,用戶不可能讀取到。
再看源碼,后面的兩個循環分別是生成彩色的帶驗證碼的圖片和在圖片上加噪點。是為了加大機器識別驗證碼的難度。最后我們看到,header('Content-Type: image/png'); 把我們這個頁面定義成為圖片的格式。
這樣,我們就可以用html代碼來讓驗證碼顯示出來:
<img src="checkcode.php" />
類似這樣:
那么驗證的過程就是,我們首先生成5個隨機字符,保存到session里。然后把這5個字符畫成一個圖片給用戶看,讓用戶識別,填寫在表單里提交后和我們session里的驗證碼比對。
其實就是這么簡單。
最后來說說驗證碼的安全性。我們emlog和wordpress其實驗證碼并不是很強大,我們這個簡單的驗證碼可以寫一個小腳本很容易地識別,所以并不適合比較大型的網站使用。像類似騰訊、百度這種網站的驗證碼很多字符能旋轉、扭曲,并且背影上的干擾物更多,甚至是中文驗證碼。不過對于小型網站來說,普通等級的驗證碼足矣防范很多刷評論的機器。
還有一點很重要,注意驗證碼使用過后要記住刪除相應的session。否則驗證碼就失去了其意義,這也是我之前犯過的錯誤。
為什么這么說。作為一個正常用戶,我們每訪問一次需要填寫驗證碼的頁面,生成驗證碼的腳本都會執行一次,也就說會生成一個新驗證碼賦值到session里,沒有任何問題。但對于一個機器(或一個暴力破解密碼腳本),它第一次訪問需要填寫驗證碼的頁面,然后在session中得到一個驗證碼,它以后就不用再次訪問這個頁面了。直接把第一次的數據包更改并再次發送即可,于是,如果沒有清除session的網站,每次的驗證碼都和第一次相同,也就喪失了驗證碼的本來作用。
這是我們做網站需要注意的地方。希望大家在寫程序的時候多注意網站的安全性,避免在網站發布后出現問題
通過網上的一些實例,拼湊出一個驗證碼登陸測試程序,詳細代碼如下:
生成驗證碼程序ttt.php,通過random生成隨機數,然后保存在session里:
login.htm頁面
- <html>
- <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head>
- <title>login</title>
- <style type="text/css">
- <!--
- .textbox {
- height: 18px;
- width: 100px;
- }
- .text {
- font-size: 14px;
- vertical-align: bottom;
- color: #0000FF;
- }
- .style1 {
- font-size: 18px;
- color: #0000FF;
- font-family: "幼圓";
- }
- -->
- </style>
- </head>
- <body>
- <table width="200">
- <tr><td align="center" valign="bottom" class="style1" bgcolor="#C7D3F9">請輸入驗證碼</td>
- </tr>
- </table>
- <form method="post" action="login.php">
- <table width="200" border="0" bgcolor="C7D3F9">
- <tr>
- <td class="text">驗證碼:</td>
- <td align="right" valign="bottom"><input type="text" name="auth" class="textbox"></td>
- </tr>
- </table>
- <img src="ttt.php?act=yes" align="middle">
- <table width="200"><tr><td align="right"><input type="button" value="看不清楚驗證碼" onclick="window.location.reload();"><input name="submit" type="submit" value="Submit"></td></tr></table>
- </form>
- </body>
- </html>
login.php
- <?php
- session_start();
- $name = $_POST['user'];
- $password = $_POST['passwd'];
- $auth = $_POST['auth'];
- #require("db.php");
- #$db = new db();
- #$sql = "select * from user where name = '$name' and password = '$password'";
- #$result = $db->query($sql);
- if($_SESSION['seccode'] == $auth)
- {
- #$_SESSION['user'] = $name;
- #$_SESSION['passwd'] = $password;
- # header("Location: main.php");
- #echo ("登錄成功!");
- $_SESSION['seccode']='';
- print '
- <script language=javascript>
- alert("登錄成功!");
- </script>';
- }else
- {
- print '
- <script language=javascript>
- alert("登錄失敗,請重新登錄!");
- self.window.location="login.html";
- </script>';
- }
- ?>
ttt.php驗證碼生成程序
- <?php
- session_start();
- function random($length, $numeric = 0) {
- mt_srand((double)microtime() * 1000000);
- if($numeric) {
- $hash = sprintf('%0'.$length.'d', mt_rand(0, pow(10, $length) - 1));
- } else {
- $hash = '';
- $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
- $max = strlen($chars) - 1;
- for($i = 0; $i < $length; $i++) {
- $hash .= $chars[mt_rand(0, $max)];
- }
- }
- return $hash;
- }
- #if(preg_replace("/https?:////([^/://]+).*/i", "//1", $_SERVER['HTTP_REFERER']) != preg_replace("/([^/:]+).*/", "//1", $_SERVER['HTTP_HOST'])) {
- # exit('Access Denied');
- #}
- //if($_GET['update']) {
- $seccode = random(4, 1);
- //}
- #if($seccode < 1 || $seccode > 9999) {
- # exit('Access Denied');
- #}
- $_SESSION['seccode'] = $seccode;
- $seccode = sprintf('%04d', $seccode);
- if(!$nocacheheaders) {
- @header("Expires: -1");
- @header("Cache-Control: no-store, private, post-check=0, pre-check=0, max-age=0", FALSE);
- @header("Pragma: no-cache");
- }
- if(function_exists('imagecreate') && function_exists('imagecolorset') && function_exists('imagecopyresized') && function_exists('imagecolorallocate') && function_exists('imagesetpixel') && function_exists('imagechar') && function_exists('imagecreatefromgif') && function_exists('imagepng')) {
- $im = imagecreate(62, 25);
- $backgroundcolor = imagecolorallocate ($im, 255, 255, 255);
- $numorder = array(1, 2, 3, 4);
- shuffle($numorder);
- $numorder = array_flip($numorder);
- for($i = 1; $i <= 4; $i++) {
- $imcodefile = 'seccode/'.$seccode[$numorder[$i]].'.gif';
- $x = $numorder[$i] * 13 + mt_rand(0, 4) - 2;
- $y = mt_rand(0, 3);
- if(file_exists($imcodefile)) {
- $imcode = imagecreatefromgif($imcodefile);
- $data = getimagesize($imcodefile);
- imagecolorset($imcode, 0 ,mt_rand(50, 255), mt_rand(50, 128), mt_rand(50, 255));
- imagecopyresized($im, $imcode, $x, $y, 0, 0, $data[0] + mt_rand(0, 6) - 3, $data[1] + mt_rand(0, 6) - 3, $data[0], $data[1]);
- } else {
- $text_color = imagecolorallocate($im, mt_rand(50, 255), mt_rand(50, 128), mt_rand(50, 255));
- imagechar($im, 5, $x + 5, $y + 3, $seccode[$numorder[$i]], $text_color);
- }
- }
- $linenums = mt_rand(10, 32);
- for($i=0; $i <= $linenums; $i++) {
- $linecolor = imagecolorallocate($im, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
- $linex = mt_rand(0, 62);
- $liney = mt_rand(0, 25);
- imageline($im, $linex, $liney, $linex + mt_rand(0, 4) - 2, $liney + mt_rand(0, 4) - 2, $linecolor);
- }
- for($i=0; $i <= 64; $i++) {
- $pointcolor = imagecolorallocate($im, mt_rand(50, 255), mt_rand(50, 255), mt_rand(50, 255));
- imagesetpixel($im, mt_rand(0, 62), mt_rand(0, 25), $pointcolor);
- }
- $bordercolor = imagecolorallocate($im , 150, 150, 150);
- imagerectangle($im, 0, 0, 61, 24, $bordercolor);
- header('Content-type: image/png');
- imagepng($im);
- imagedestroy($im);
- } else {
- $numbers = array
- (
- 0 => array('3c','66','66','66','66','66','66','66','66','3c'),
- 1 => array('1c','0c','0c','0c','0c','0c','0c','0c','1c','0c'),
- 2 => array('7e','60','60','30','18','0c','06','06','66','3c'),
- 3 => array('3c','66','06','06','06','1c','06','06','66','3c'),
- 4 => array('1e','0c','7e','4c','2c','2c','1c','1c','0c','0c'),
- 5 => array('3c','66','06','06','06','7c','60','60','60','7e'),
- 6 => array('3c','66','66','66','66','7c','60','60','30','1c'),
- 7 => array('30','30','18','18','0c','0c','06','06','66','7e'),
- 8 => array('3c','66','66','66','66','3c','66','66','66','3c'),
- 9 => array('38','0c','06','06','3e','66','66','66','66','3c')
- );
- for($i = 0; $i < 10; $i++) {
- for($j = 0; $j < 6; $j++) {
- $a1 = substr('012', mt_rand(0, 2), 1).substr('012345', mt_rand(0, 5), 1);
- $a2 = substr('012345', mt_rand(0, 5), 1).substr('0123', mt_rand(0, 3), 1);
- mt_rand(0, 1) == 1 ? array_push($numbers[$i], $a1) : array_unshift($numbers[$i], $a1);
- mt_rand(0, 1) == 0 ? array_push($numbers[$i], $a1) : array_unshift($numbers[$i], $a2);
- }
- }
- $bitmap = array();
- for($i = 0; $i < 20; $i++) {
- for($j = 0; $j < 4; $j++) {
- $n = substr($seccode, $j, 1);
- $bytes = $numbers[$n][$i];
- $a = mt_rand(0, 14);
- switch($a) {
- case 1: str_replace('9', '8', $bytes); break;
- case 3: str_replace('c', 'e', $bytes); break;
- case 6: str_replace('3', 'b', $bytes); break;
- case 8: str_replace('8', '9', $bytes); break;
- case 0: str_replace('e', 'f', $bytes); break;
- }
- array_push($bitmap, $bytes);
- }
- }
- for($i = 0; $i < 8; $i++) {
- $a = substr('012', mt_rand(0, 2), 1) . substr('012345', mt_rand(0, 5), 1);
- array_unshift($bitmap, $a);
- array_push($bitmap, $a);
- }
- $image = pack('H*', '424d9e000000000000003e000000280000002000000018000000010001000000'.
- '0000600000000000000000000000000000000000000000000000FFFFFF00'.implode('', $bitmap));
- header('Content-Type: image/bmp');
- echo $image;
- }
- ?>
新聞熱點
疑難解答