php表单加入Token防止重复提交的方法分析


Posted in PHP onOctober 10, 2016

本文实例讲述了php表单加入Token防止重复提交的方法。分享给大家供大家参考,具体如下:

Token浅谈

Token,就是令牌,最大的特点就是随机性,不可预测。一般黑客或软件无法猜测出来。

那么,Token有什么作用?又是什么原理呢?

Token一般用在两个地方——防止表单重复提交、anti csrf攻击(跨站点请求伪造)。

两者在原理上都是通过session token来实现的。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。

然后,如果应用于“anti csrf攻击”,则服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。

不过,如果应用于“防止表单重复提交”,服务器端第一次验证相同过后,会将涩session中的Token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token没变,但服务器端session中Token已经改变了。

上面的session应用相对安全,但也叫繁琐,同时当多页面多请求时,必须采用多Token同时生成的方法,这样占用更多资源,执行效率会降低。因此,也可用cookie存储验证信息的方法来代替session Token。比如,应对“重复提交”时,当第一次提交后便把已经提交的信息写到cookie中,当第二次提交时,由于cookie已经有提交记录,因此第二次提交会失败。

不过,cookie存储有个致命弱点,如果cookie被劫持(xss攻击很容易得到用户cookie),那么又一次gameover。黑客将直接实现csrf攻击。

php表单加入Token防止重复提交的方法分析

所以,安全和高效相对的。具体问题具体对待吧。

php表单加入Token防止重复提交

原理在于生成一个随机字符串放在session里,提交表单后来验证这个字符串,可以做到防止他人自己写form来欺骗提交,重复提交或者双击提交。

php表单加入Token防止重复提交的方法分析

简单的用php实现的代码如下:

<?php
/*
* PHP简单利用token防止表单重复提交
* 此处理方法纯粹是为了给初学者参考
*/
session_start();
function set_token() {
  $_SESSION['token'] = md5(microtime(true));
}
function valid_token() {
  $return = $_REQUEST['token'] === $_SESSION['token'] ? true : false;
  set_token();
  return $return;
}
//如果token为空则生成一个token
if(!isset($_SESSION['token']) || $_SESSION['token']=='') {
  set_token();
}
if(isset($_POST['test'])){
  if(!valid_token()){
    echo "token error";
  }else{
    echo '成功提交,Value:'.$_POST['test'];
  }
}
?>
<form method="post" action="">
  <input type="hidden" name="token" value="<?php echo $_SESSION['token']?>">
  <input type="text" name="test" value="Default">
  <input type="submit" value="提交" />
</form>

上面的比较简单一点的方法,下面的代码更加安全一点。

Token.php

<?php
/*
 * Created on 2013-3-25
 *
 * To change the template for this generated file go to
 * Window - Preferences - PHPeclipse - PHP - Code Templates
 */
function getToken($len = 32, $md5 = true) {
  # Seed random number generator
  # Only needed for PHP versions prior to 4.2
  mt_srand((double) microtime() * 1000000);
  # Array of characters, adjust as desired
  $chars = array (
    'Q',
    '@',
    '8',
    'y',
    '%',
    '^',
    '5',
    'Z',
    '(',
    'G',
    '_',
    'O',
    '`',
    'S',
    '-',
    'N',
    '<',
    'D',
    '{',
    '}',
    '[',
    ']',
    'h',
    ';',
    'W',
    '.',
    '/',
    '|',
    ':',
    '1',
    'E',
    'L',
    '4',
    '&',
    '6',
    '7',
    '#',
    '9',
    'a',
    'A',
    'b',
    'B',
    '~',
    'C',
    'd',
    '>',
    'e',
    '2',
    'f',
    'P',
    'g',
    ')',
    '?',
    'H',
    'i',
    'X',
    'U',
    'J',
    'k',
    'r',
    'l',
    '3',
    't',
    'M',
    'n',
    '=',
    'o',
    '+',
    'p',
    'F',
    'q',
    '!',
    'K',
    'R',
    's',
    'c',
    'm',
    'T',
    'v',
    'j',
    'u',
    'V',
    'w',
    ',',
    'x',
    'I',
    '$',
    'Y',
    'z',
    '*'
  );
  # Array indice friendly number of chars;
  $numChars = count($chars) - 1;
  $token = '';
  # Create random token at the specified length
  for ($i = 0; $i < $len; $i++)
    $token .= $chars[mt_rand(0, $numChars)];
  # Should token be run through md5?
  if ($md5) {
    # Number of 32 char chunks
    $chunks = ceil(strlen($token) / 32);
    $md5token = '';
    # Run each chunk through md5
    for ($i = 1; $i <= $chunks; $i++)
      $md5token .= md5(substr($token, $i * 32 - 32, 32));
    # Trim the token
    $token = substr($md5token, 0, $len);
  }
  return $token;
}
?>

form.php

<?php
include_once("token.php");
$token = getToken();
session_start();
$_SESSION['token'] = $token;
?>
<form action="action.php" method="post"
<input type="hidden" name="token" value="<?=$token?>" />
<!-- 其他input submit之类的 -->
</form>

action.php

<?php
session_start();
if($_POST['token'] == $_SESSION['token']){
  unset($_SESSION['token']);
  echo "这是一个正常的提交请求";
}else{
  echo "这是一个非法的提交请求";
}
?>

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP 字符串加密函数(在指定时间内加密还原字符串,超时无法还原)
Apr 28 PHP
php中函数的形参与实参的问题说明
Sep 01 PHP
php获取数组元素中头一个数组元素值的实现方法
Dec 20 PHP
php采集内容中带有图片地址的远程图片并保存的方法
Jan 03 PHP
Apache服务器下防止图片盗链的办法
Jul 06 PHP
PHP如何实现Unicode和Utf-8编码相互转换
Jul 29 PHP
Yii使用技巧大汇总
Dec 29 PHP
php使用pclzip类实现文件压缩的方法(附pclzip类下载地址)
Apr 30 PHP
Yii2 RESTful中api的使用及开发实例详解
Jul 06 PHP
php 访问oracle 存储过程实例详解
Jan 08 PHP
YII分模块加载路由的实现方法
Oct 01 PHP
thinkphp3.2同时连接两个数据库的简单方法
Aug 13 PHP
Laravel5中防止XSS跨站攻击的方法
Oct 10 #PHP
php中让人头疼的浮点数运算分析
Oct 10 #PHP
Laravel实现自定义错误输出内容的方法
Oct 10 #PHP
PHP定时任务获取微信access_token的方法
Oct 10 #PHP
php使用SAE原生Mail类实现各种类型邮件发送的方法
Oct 10 #PHP
PHP简单数据库操作类实例【支持增删改查及链式操作】
Oct 10 #PHP
Ajax实现对静态页面的文章访问统计功能示例
Oct 10 #PHP
You might like
全国FM电台频率大全 - 19 广东省
2020/03/11 无线电
php 中英文语言转换类代码
2011/08/11 PHP
解析php addslashes()与addclashes()函数的区别和比较
2013/06/24 PHP
PHP框架Swoole定时器Timer特性分析
2014/08/19 PHP
PHP函数超时处理方法
2016/02/14 PHP
Thinkphp5.0 框架的请求方式与响应方式分析
2019/10/14 PHP
PHP7 字符串处理机制修改
2021/03/09 PHP
javascript 文本框水印/占位符(watermark/placeholder)实现方法
2012/01/15 Javascript
nodejs中exports与module.exports的区别详细介绍
2013/01/14 NodeJs
在js文件中如何获取basePath处理js路径问题
2013/07/10 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
为什么JavaScript没有块级作用域
2016/05/22 Javascript
全面解析JavaScript里的循环方法之forEach,for-in,for-of
2020/04/20 Javascript
老生常谈JavaScript数组的用法
2016/06/10 Javascript
Vue实现选择城市功能
2017/05/27 Javascript
运用jQuery写的验证表单(实例讲解)
2017/07/06 jQuery
在一个页面实现两个zTree联动的方法
2017/12/20 Javascript
js中int和string数据类型互相转化实例
2019/01/16 Javascript
javascript实现的字符串转换成数组操作示例
2019/06/13 Javascript
Vue 如何使用props、emit实现自定义双向绑定的实现
2020/06/05 Javascript
[48:48]完美世界DOTA2联赛PWL S3 Magama vs GXR 第一场 12.19
2020/12/24 DOTA
实例Python处理XML文件的方法
2015/08/31 Python
TensorFLow用Saver保存和恢复变量
2018/03/10 Python
Python基于FTP模块实现ftp文件上传操作示例
2018/04/23 Python
使用Python实现一个栈判断括号是否平衡
2018/08/23 Python
使用Python进行目录的对比方法
2018/11/01 Python
wxPython之wx.DC绘制形状
2019/11/19 Python
python中取绝对值简单方法总结
2020/07/24 Python
详解如何使用rem或viewport进行移动端适配
2020/08/14 HTML / CSS
易程科技软件测试笔试
2013/03/24 面试题
战略性融资合作协议书范本
2014/10/17 职场文书
2014年办公室文秘工作总结
2014/12/09 职场文书
食品安全责任书范本
2015/05/09 职场文书
大学毕业谢师宴致辞
2015/07/27 职场文书
送给小学生的暑假礼物!小学生必背99首古诗
2019/07/02 职场文书
python实现简单区块链结构
2021/04/25 Python