PHP Token(令牌)设计


Posted in PHP onMarch 15, 2008

如何达到目的:

怎样避免重复提交?
在SESSION里要存一个数组,这个数组存放以经成功提交的token.在后台处理时,先判断这个token是否在这个数组里,如果存在,说明是重复提交. 
如何检查来路?
可选项,这个token在生成的时候,加入了当前的session_id.如果别人copy你的html(token一迸copy),在提交时,理论上token里包含的session_id不等于当前session_id,就可以判断这次提交是外部提交. 
如何匹配要执行的动作?
在token的时候,要把这个token的动作名称写进这个token里,这样,在处理的时候,把这个动作解出来进行比较就行了.
我以前写的GToken不能达到上面所说的第二条,今天修改了一下,把功能2加上了.个人感觉还行.
请大家看代码,感觉哪里有不合理的地方,还请赐教!谢谢.

加密我是找的网上的一个方法,稍作了一下修改.

GEncrypt.inc.php:

<?php  
class GEncrypt extends GSuperclass {  
    protected static function keyED($txt,$encrypt_key){     
        $encrypt_key = md5($encrypt_key);     
        $ctr=0;     
        $tmp = "";     
        for ($i=0;$i<strlen($txt);$i++){     
            if ($ctr==strlen($encrypt_key)) $ctr=0;     
            $tmp.= substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1);     
            $ctr++;     
        }     
        return $tmp;     
    }      public static function encrypt($txt,$key){     
        //$encrypt_key = md5(rand(0,32000));  
        $encrypt_key = md5(((float) date("YmdHis") + rand(10000000000000000,99999999999999999)).rand(100000,999999));  
        $ctr=0;     
        $tmp = "";     
        for ($i=0;$i<strlen($txt);$i++){  
            if ($ctr==strlen($encrypt_key)) $ctr=0;     
            $tmp.= substr($encrypt_key,$ctr,1) . (substr($txt,$i,1) ^ substr($encrypt_key,$ctr,1));     
            $ctr++;     
        }     
        return base64_encode(self::keyED($tmp,$key));  
    }  
    public static function decrypt($txt,$key){  
        $txt = self::keyED( base64_decode($txt),$key);     
        $tmp = "";  
        for ($i=0;$i<strlen($txt);$i++){     
            $md5 = substr($txt,$i,1);     
            $i++;     
            $tmp.= (substr($txt,$i,1) ^ $md5);     
        }  
        return $tmp;  
    }      
}  
?> 

GToken.inc.php
方法:

a,granteToken 参数:formName,即动作名称,key是加密/解密 密钥.
返回一个字符串,形式是: 加密(formName:session_id)

b,isToken 参数:token 即granteToken产生的结果,formName,动作名称,fromCheck是否检查来路,如果为真,还要判断token里的session_id是否和当前的session_id一至.

c,dropToken,当成功执行一个动作后,调用这个函数,把这个token记入session里,

<?php  
/**  
* 原理:请求分配token的时候,想办法分配一个唯一的token, base64( time + rand + action)  
* 如果提交,将这个token记录,说明这个token以经使用,可以跟据它来避免重复提交。  
*  
*/  
class GToken {      /**  
     * 得到当前所有的token  
     *  
     * @return array  
     */  
    public static function getTokens(){  
        $tokens = $_SESSION[GConfig::SESSION_KEY_TOKEN ];  
        if (empty($tokens) && !is_array($tokens)) {  
            $tokens = array();  
        }  
        return $tokens;  
    }  
    /**  
     * 产生一个新的Token  
     *  
     * @param string $formName  
     * @param 加密密钥 $key  
     * @return string  
     */  
    public static function granteToken($formName,$key = GConfig::ENCRYPT_KEY ){  
        $token = GEncrypt::encrypt($formName.":".session_id(),$key);  
        return $token;  
    }  
    /**  
     * 删除token,实际是向session 的一个数组里加入一个元素,说明这个token以经使用过,以避免数据重复提交。  
     *  
     * @param string $token  
     */  
    public static function dropToken($token){  
        $tokens = self::getTokens();  
        $tokens[] = $token;  
        GSession::set(GConfig::SESSION_KEY_TOKEN ,$tokens);  
    }  
    /**  
     * 检查是否为指定的Token  
     *  
     * @param string $token    要检查的token值  
     * @param string $formName  
     * @param boolean $fromCheck 是否检查来路,如果为true,会判断token中附加的session_id是否和当前session_id一至.  
     * @param string $key 加密密钥  
     * @return boolean  
     */  
    public static function isToken($token,$formName,$fromCheck = false,$key = GConfig::ENCRYPT_KEY){  
        $tokens = self::getTokens();  
        if (in_array($token,$tokens)) //如果存在,说明是以使用过的token  
            return false;  
        $source = split(":", GEncrypt::decrypt($token,$key));  
        if($fromCheck)  
            return $source[1] == session_id() && $source[0] == $formName;  
        else  
            return $source[0] == $formName;  
    }  
}  
?> 
示例:

首先从$_POST里取出token,用isToken判断.

PHP Token(令牌)设计下载此文件这一切看着似乎是没有问题了.
如果想判断是否是执行的匹配动作,可以把isToken里的formName改一下,运行,很好,没有匹配上.证明这个成功.

是否能避免重复提交,我没有验证,太简单的逻辑了.

余下的就是判断 来路检查 是否正常工作了.
把上面的示例产生的html copy到本地的一个网页内(以达到不同的域的目的),运行,检查来路不明,没有执行动作(需要把isToken的第三个参数设为true).
把isToken的第三个参数设置为false,提交,指定的动作执行了!

好了,到此为止,不知道哪个地方是否还存在BUG,这就要在长期运用中慢慢调试修改了!

PHP 相关文章推荐
php中显示数组与对象的实现代码
Apr 18 PHP
PHP多个版本的分析解释
Jul 21 PHP
浅析php header 跳转
Jun 17 PHP
Yii中使用PHPExcel导出Excel的方法
Dec 26 PHP
PHP的几个常用加密函数
Feb 03 PHP
详谈PHP程序Laravel 5框架的优化技巧
Jul 18 PHP
PHP实现表单提交时去除斜杠的方法
Dec 26 PHP
PHP实现图片批量打包下载功能
Mar 01 PHP
如何通过View::first使用Laravel Blade的动态模板详解
Sep 21 PHP
PHP中危险的file_put_contents函数详解
Nov 04 PHP
php取出数组单个值的方法
Mar 12 PHP
TP5框架页面跳转样式操作示例
Apr 05 PHP
php项目打包方法
Feb 18 #PHP
PHP4与PHP5的时间格式问题
Feb 17 #PHP
PHP5 面向对象程序设计
Feb 13 #PHP
Dedecms常用函数解析
Feb 01 #PHP
用php实现批量查询清除一句话后门的代码
Jan 20 #PHP
asp和php下textarea提交大量数据发生丢失的解决方法
Jan 20 #PHP
php开发工具之vs2005图解
Jan 12 #PHP
You might like
坏狼php学习 计数器实例代码
2008/06/15 PHP
如何取得中文字符串中出现次数最多的子串
2013/08/08 PHP
php接口与接口引用的深入解析
2013/08/09 PHP
让PHP显示Facebook的粉丝数量方法
2014/01/08 PHP
Thinkphp中的curd应用实用要点
2015/01/04 PHP
php检查是否是ajax请求的方法
2015/04/16 PHP
phpstorm 正则匹配删除空行、注释行(替换注释行为空行)
2018/01/21 PHP
分享别人写的一个小型js框架
2007/08/13 Javascript
JavaScript中操作字符串小结
2015/05/04 Javascript
jquery读取xml文件实现省市县三级联动的方法
2015/05/29 Javascript
jQuery实现的经典竖向伸缩菜单效果代码
2015/09/24 Javascript
JavaScript、jQuery与Ajax的关系
2016/01/24 Javascript
JavaScript使用键盘输入控制实现数字验证功能
2016/08/19 Javascript
Angular.JS学习之依赖注入$injector详析
2016/10/20 Javascript
JSON中key动态设置及JSON.parse和JSON.stringify()的区别
2016/12/29 Javascript
canvas绘制的直线动画
2017/01/23 Javascript
谈谈JavaScript数组常用方法总结
2017/01/24 Javascript
在javaScript中检测数据类型的几种方式小结
2017/03/04 Javascript
Bootstrap图片轮播效果详解
2017/10/17 Javascript
浅谈ElementUI中switch回调函数change的参数问题
2018/08/24 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
[02:16]卖萌的僵尸 DOTA2神话信使飞僵小宝来袭
2014/03/24 DOTA
[51:39]DOTA2-DPC中国联赛 正赛 Magma vs LBZS BO3 第二场 2月7日
2021/03/11 DOTA
基于Python实现的百度贴吧网络爬虫实例
2015/04/17 Python
详解详解Python中writelines()方法的使用
2015/05/25 Python
python实现根据主机名字获得所有ip地址的方法
2015/06/28 Python
python rolling regression. 使用 Python 实现滚动回归操作
2020/06/08 Python
ShellScript面试题一则-ShellScript编程
2014/03/05 面试题
几个Shell Script面试题
2012/08/31 面试题
餐饮主管岗位职责
2013/12/10 职场文书
美容院营销方案
2014/03/05 职场文书
2015年安全生产责任书
2015/01/30 职场文书
2015年房地产个人工作总结
2015/05/26 职场文书
毕业生自我鉴定范文
2019/05/13 职场文书
如何在Mac上通过docker配置PHP开发环境
2021/05/29 PHP
gtx1650怎么样 gtx1650显卡相当于什么级别
2022/04/08 数码科技