PHP实现“挑战-应答”方式的登陆模型

来源:互联网 发布:php抓取新闻 编辑:程序博客网 时间:2024/04/30 01:12

PHP实现“挑战-应答”方式的登陆模型

 

内容提要

1.       什么是“挑战-应答”系统

2.       关于HMAC

3.       登陆模型的流程与相关代码

 

“挑战-应答”

定义  假设用户U想向系统S认证自己。设US有一个协商好的秘密函数f。挑战-应答认证系统就是这样的一个系统:S发送一个随机消息m(挑战)给U,用户U回应m的变形r=fm(应答)。S通过独立计算r来验证r

根据上面的定义,在一个典型的C/S系统中,认证过程为:

1) 客户向认证服务器发出请求,要求进行身份认证;

2) 认证服务器从用户数据库中查询用户是否是合法的用户,若不是,则不做进一步处理;

3) 认证服务器内部产生一个随机数,作为“提问”,发送给客户;

4) 客户将用户名字和随机数合并,使用单向Hash函数(例如MD5算法)生成一个字节串作为应答;

5) 认证服务器将应答串与自己的计算结果比较,若二者相同,则通过一次认证;否则,认证失败;

6) 认证服务器通知客户认证成功或失败。

 

在一个C/S项目中,1~3步其实就是客户端请求登陆页面的一个过程。到了第四步,客户将用户名字和随机数合并,生成应答,这个过程使用服务器计算的方式还是在客户端就计算好?使用的函数fm又是怎样选择呢?在这里我的办法是,引入HMAC

HMAC

定义  计算HMAC需要一个散列函数hash(可以是md5或者sha-1)和一个密钥key。用L表示hash函数输出字符串长(md516),用B表示数据块的长度(md5sha-1的分割数据块长都是64)。密钥key的长度可以小于等于数据块长B,如果大于数据块长度,可以使用hash函数对key进行转换,结果就是一个L长的key

然后创建两个B长的不同字符串:

  innerpad = 长度为B 0×36

  outterpad = 长度为B 0×5C

计算输入字符串strHMAC

  hash(key ^ outterpad, hash(key ^ innerpad, str))

HMAC主要应用在身份验证中,它的使用方法是这样的:

  1. 客户端发出登录请求(假设是浏览器的GET请求)

  2. 服务器返回一个随机值,并在会话中记录这个随机值

  3. 客户端将该随机值作为密钥,用户密码进行HMAC运算,然后提交给服务器

  4. 服务器读取用户数据库中的用户密码和步骤2中发送的随机值做与客户端一样的HMAC运算,然后与用户发送的结果比较,如果结果一致则验证用户合法。

在这个过程中,可能遭到安全攻击的是服务器发送的随机值和用户发送的HMAC结果,而对于截获了这两个值的黑客而言这两个值是没有意义的,绝无获取用户密码的可能性,随机值的引入使HMAC只在当前会话中有效,大大增强了安全性和实用性。大多数的语言都实现了HMAC算法,比如phpmhashpythonhmac.pyjavaMessageDigest类,在web验证中使用HMAC也是可行的,用js进行md5运算的速度也是比较快的。事实上,客户端中使用js来计算HMAC,返回结果,在服务器中调用PHPmhash计算后与客户端返回的结果进行比较。这样做的好处是,服务器避免了重复计算,而且由于客户端在返回结果的过程中,所提交的数据由于经过了HAMC的加密,安全性得到了进一步的提高。

根据上面的分析,整个登陆的模型的设计已经十分明了。由于项目采用的是PHP做为开发语言,同时采用Codeigniter作为框架。相关代码如下:

1.       客户向认证服务器发出请求,要求进行身份认证。这个过程由Login Controller控制,返回用户登陆的页面。其中客户端用来计算HMACjs可以在这里下载:

http://pajhome.org.uk/crypt/md5/md4.js

LoginView.php

  1. <?php $attributes = array('onSubmit'=>'javascript:return hex_hmac_md5(key.value, hex_md5(password.value))',
  2. 'name' => 'loginForm''id' => 'loginForm'); ?>
  3. <?=form_open('login/check_user'$attributes);?>
  4. //HTML代码,略
  5. <tr>
  6. <td width="30%" align="right" height="25">用户名:</td>
  7. <td align="left"><input name="username" value="" type="text" style="width:130px;" /></td></tr>
  8. <tr><td align="right" height="25">密 码:<input type="hidden" name="key" value=<?=$key; ?> /></td>
  9. <td align="left"><input name="password" type="password" value="" style="width:130px;" /></td></tr>

      实现的效果如下:

User name
Password

2.       服务器端校验同样由Login Controller控制,调用Model,查询数据库,同时进行校验,并将结果返回Login Controller

LoginModel.php

  1. <?php
  2. class user_model extends Model {
  3.     
  4.     function __construct() {
  5.         parent::Model();
  6.         //$this->load->library('Hex_hmac');
  7.     }
  8.     
  9.     function authenticate($username,$password,$key){
  10.         $query = $this->db->get_where('user',array('username'=>$username));
  11.         $admin = $query->row();
  12.         if($admin){
  13.             $data=$admin->password;
  14.             $result=bin2hex (mhash(MHASH_MD5, $data, $key));
  15.             // 若没有启用php_mhash.dll(libmhash) 扩展则使用下面的方式
  16.             //$result=$this->hex_hmac->hmac($key,$data);            
  17.             if($result == $password){
  18.                 return TRUE;
  19.             }else{
  20.                 return FALSE;
  21.             }
  22.         }else{
  23.             return FALSE;
  24.         }
  25.     }
  26.     
  27.     // 一般的登陆模型:
  28.     function validate_user($username,$password){
  29.         // 用select 1 比较好
  30.         $sql="SELECT 1 FROM user WHERE username = ? AND password = md5(?)";
  31.         $query=$this->db->query($sql,array('username'=>$username,'password'=>$password));
  32.         if ($query->num_rows() > 0) {
  33.             return TRUE;            
  34.         } else {
  35.             return FALSE;
  36.         }
  37.     }
  38. }
  39. ?>

3.       “挑战”即SALT的生成,这里采用的是用PHP生成随机字符串并传到客户端的办法。HMAC与一般的加密重要的区别在于它具有“瞬时”性,即认证只在当时有效。因此用户每次登陆,都将产生新的SALT,故这里并没用加密SALT

生成SALT的函数如下:

  1. function createKey($length=6) {
  2.     $hash = '';
  3.     $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
  4.     $max = strlen ( $chars ) - 1;
  5.     mt_srand ( ( double ) microtime () * 1000000 );
  6.     for($i = 0; $i < $length$i ++) {
  7.         $hash .= $chars [mt_rand ( 0, $max )];
  8.     }
  9.     return $hash;
  10. }

问题与分析

1.       JavaScript被禁用的情形。很明显,这种情况发生的几率很大——无论是用户的浏览器不支持还是浏览器的设置。在这种情况下,解决的方法只有两个:一是屏蔽这类用户的登陆;二是采用没加密的方式登陆。很明显,采用后者是一个明智的做法,因为这只需对现有的模型稍作修改即可。例如,在用户输入的表单中,增加一个“Hidden field”,在服务器端校验用户返回的结果前,先检查这个“Hidden field”是否经过Hash计算,如否则采用服务器进行两次计算的方式进行校验的过程。

2.       空值问题。这几乎不算一个问题,如果在一般的登陆模型中的话,因为无论是采用客户端js校验或者服务器端校验都能很好解决这个问题。而在这个登陆模型中,事情有一点不一样:经过HMAC计算,即使是空值,也能返回结果!当然,在只需在客户端中增加一段校验的js即可。

3.       SALT的产生。SALT由于在客户端和服务器端中要保持同步,产生SALT的函数在登录的过程中务必确保只调用了一次。这里的实现方法是,在登陆中增加一个SALT的“Hidden field”,提交结果的同时,也提交SALT供服务器计算。

4.       Password字段的加密。很明显,采用了“挑战-应答”的登陆方式,由于在返回数据之前就已经进行加密,安全性得到很大的提高。而在一般的网站系统中都采用了md5作为加密的方式。但是目前一些网站提供了关于MD5解密后密码和明密的数据库记录,有些网站的记录有上亿条,可以很快查出一次加密后的明码。针对一些弱口令,据说已经达到70%左右。因此采用了md5重复加密的方式,但是由于md5采用单向加密,相同的明文,密码一定是一样的。为什么不能采用与登陆时采用的HMAC?显然,由于HMAC需要随机的SALT,这增加了解密的复杂度。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 头发油的特别快怎么办 头发很油 又少怎么办 头发两天就油了怎么办 头发被剪的很丑怎么办 美发师年龄大了怎么办 青春期头发掉的厉害怎么办 剪了短发头发翘怎么办 4个月婴儿咳嗽怎么办 2个月婴儿咳嗽怎么办 5个月婴儿咳嗽怎么办 烫的内扣睡觉怎么办 站了一天腿疼怎么办 头发被剪得很丑怎么办 淹脖子破皮了怎么办 孩子胖脖子淹了怎么办 宝宝屁股破皮了怎么办 新生儿屁屁发红及烂怎么办 头发烫完太蓬松怎么办 头发烫的太卷了怎么办 烫了卷发很毛躁怎么办 烫发后头发干枯毛躁怎么办 烫完头发掉发怎么办 烫发掉发严重该怎么办 烫头发后掉头发怎么办 烫过头发后毛躁怎么办 烫了头发像大妈怎么办 头发烫了之后很毛躁怎么办 鳄龟爪子烂了怎么办 乌龟壳边缘烂了怎么办 乌龟拉绿色的水怎么办 小乌龟龟壳变软怎么办 鳄龟不待在水里怎么办 脖子整天黏黏的怎么办 有脊椎侧弯跳舞怎么办 落枕10天还不好怎么办 落枕十几天没好怎么办 肩一边高一边低怎么办 35岁无稳定工作怎么办 机械手表走的快怎么办 机械表发条紧了怎么办 两只乌龟互相咬怎么办?