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动态生成虚拟现实VRML网页
Oct 09 PHP
php 方便水印和缩略图的图形类
May 21 PHP
PHP数据库调用类调用实例(详细注释)
Jul 12 PHP
php中的PHP_EOL换行符详细解析
Oct 26 PHP
PHP中mysql_field_type()函数用法
Nov 24 PHP
php+mysql数据库查询实例
Jan 21 PHP
使用PHP和JavaScript判断请求是否来自微信内浏览器
Aug 18 PHP
php连接微软MSSQL(sql server)完全攻略
Nov 27 PHP
在php7中MongoDB实现模糊查询的方法详解
May 03 PHP
Laravel5框架添加自定义辅助函数的方法
Aug 01 PHP
ThinkPHP框架结合Ajax实现用户名校验功能示例
Jul 03 PHP
如何用Laravel包含你自己的帮助函数
May 27 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
重量级动漫纷纷停播!唯独OVERLORD第四季正在英魂之刃继续更新
2020/05/06 日漫
索尼SONY ICF-7600A(W)电路分析
2021/03/01 无线电
Yii2中关联查询简单用法示例
2016/08/10 PHP
PHP实现的分解质因数操作示例
2018/08/01 PHP
PHP PDOStatement::closeCursor讲解
2019/01/30 PHP
JS基础之undefined与null的区别分析
2011/08/08 Javascript
JavaScript对象学习经验整理
2013/10/12 Javascript
js隐式全局变量造成的bug示例代码
2014/04/22 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
JQuery boxy插件在IE中边角图片不显示问题的解决
2015/05/20 Javascript
深入理解JS addLoadEvent函数
2016/05/20 Javascript
微信小程序 教程之WXSS
2016/10/18 Javascript
基于jQuery实现咖啡订单管理简单应用
2017/02/10 Javascript
JavaScript中利用Array filter() 方法压缩稀疏数组
2018/02/24 Javascript
webpack external模块的具体使用
2018/03/10 Javascript
vue.js项目 el-input 组件 监听回车键实现搜索功能示例
2018/08/25 Javascript
js实现无刷新监听URL的变化示例代码详解
2020/06/03 Javascript
vue如何使用外部特殊字体的操作
2020/07/30 Javascript
[02:51]DOTA2战队出征照拍摄花絮 TI3明星化身时尚男模
2013/07/22 DOTA
Django管理员账号和密码忘记的完美解决方法
2018/12/06 Python
Django与pyecharts结合的实例代码
2020/05/13 Python
Python如何爬取b站热门视频并导入Excel
2020/08/10 Python
python获取百度热榜链接的实例方法
2020/08/25 Python
python 如何使用find和find_all爬虫、找文本的实现
2020/10/16 Python
使用Python爬取Json数据的示例代码
2020/12/07 Python
多视角3D逼真HTML5水波动画
2016/03/03 HTML / CSS
Lookfantastic澳大利亚官网:英国知名美妆购物网站
2021/01/07 全球购物
初中生物教学反思
2014/01/10 职场文书
大学社团活动总结
2014/04/26 职场文书
开服装店计划书
2014/08/15 职场文书
会计电算化实训报告
2014/11/04 职场文书
2014年村党支部工作总结
2014/12/04 职场文书
谢师宴学生答谢词
2015/09/30 职场文书
六一儿童节致辞稿(3篇)
2019/07/11 职场文书
sql查询结果列拼接成逗号分隔的字符串方法
2021/05/25 SQL Server
解析目标检测之IoU
2021/06/26 Python