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的分页功能
Mar 21 PHP
dedecms系统常用术语汇总
Apr 03 PHP
php入门学习知识点二 PHP简单的分页过程与原理
Jul 14 PHP
使用PHP获取汉字的拼音(全部与首字母)
Jun 27 PHP
php实现加减法验证码代码
Feb 14 PHP
php将图片保存入mysql数据库失败的解决方法
Dec 27 PHP
PHP中获取文件创建日期、修改日期、访问时间的方法
Nov 05 PHP
Yii CDBCriteria常用方法实例小结
Jan 19 PHP
php面向对象的用户登录身份验证
Jun 08 PHP
PHP实现的观察者模式实例
Jun 21 PHP
完美的php分页类
Oct 24 PHP
PhpStorm 2020.3:新增开箱即用的PHP 8属性(推荐)
Oct 30 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
PHP使用strtotime计算两个给定日期之间天数的方法
2015/03/18 PHP
无需数据库在线投票调查php代码
2016/07/20 PHP
PHP反射学习入门示例
2019/06/14 PHP
PHP过滤器 filter_has_var() 函数用法实例分析
2020/04/23 PHP
JObj预览一个JS的框架
2008/03/13 Javascript
javascript web对话框与弹出窗口
2009/02/22 Javascript
类似CSDN图片切换效果脚本
2009/09/17 Javascript
csdn 论坛技术区平均给分功能
2009/11/07 Javascript
关于jquery append() html时的小问题的解决方法
2010/12/16 Javascript
js在指定位置增加节点函数insertBefore()用法实例
2015/01/12 Javascript
jQuery内容过滤选择器用法分析
2015/02/10 Javascript
JavaScript简介
2015/02/15 Javascript
浅谈JavaScript中的string拥有方法的原因
2015/08/28 Javascript
详解angularjs中的隔离作用域理解以及绑定策略
2017/05/31 Javascript
Angular4实现动态添加删除表单输入框功能
2017/08/11 Javascript
深入理解ES6学习笔记之块级作用域绑定
2017/08/19 Javascript
Angular搜索 过滤 批量删除 添加 表单验证功能集锦(实例代码)
2017/10/25 Javascript
基于滚动条位置判断的简单实例
2017/12/14 Javascript
vue2.0获取鼠标位置的方法
2018/09/13 Javascript
Vue+elementUI实现多图片上传与回显功能(含回显后继续上传或删除)
2020/03/23 Javascript
vue.js实现点击图标放大离开时缩小的代码
2021/01/27 Vue.js
Python递归函数定义与用法示例
2017/06/02 Python
Python 列表理解及使用方法
2017/10/27 Python
Python使用pylab库实现绘制直方图功能示例
2018/06/01 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
有关Tensorflow梯度下降常用的优化方法分享
2020/02/04 Python
使用python检查yaml配置文件是否符合要求
2020/04/09 Python
pycharm 配置svn的图文教程(手把手教你)
2021/01/15 Python
快速一键生成Python爬虫请求头
2021/03/04 Python
意大利综合购物网站:Giordano Shop
2016/10/21 全球购物
数据库面试要点基本概念
2013/10/31 面试题
英语系本科生个人求职信
2013/09/21 职场文书
学年自我鉴定范文
2013/10/01 职场文书
建筑工程催款函
2015/06/24 职场文书
一次MySQL启动导致的事故实战记录
2021/09/15 MySQL
javascript的setTimeout()使用方法总结
2021/11/20 Javascript