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 相关文章推荐
如何分别全角和半角以避免乱码
Oct 09 PHP
php下连接ftp实现文件的上传、下载、删除文件实例代码
Jun 03 PHP
PHP目录函数实现创建、读取目录教程实例
Jan 13 PHP
php增删改查示例自己写的demo
Sep 04 PHP
调试PHP程序的多种方法介绍
Nov 06 PHP
php压缩和解压缩字符串的方法
Mar 14 PHP
Laravel 5框架学习之路由、控制器和视图简介
Apr 07 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
May 23 PHP
PHP自定义多进制的方法
Nov 03 PHP
ThinkPHP实现简单登陆功能
Apr 28 PHP
ThinkPHP框架实现的MySQL数据库备份功能示例
May 24 PHP
PHP7 标准库修改
Mar 09 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日历[测试通过]
2008/03/27 PHP
phpQuery占用内存过多的处理方法
2013/11/13 PHP
PHP 8新特性简介
2020/08/18 PHP
YUI 读码日记之 YAHOO.util.Dom - Part.1
2008/03/22 Javascript
菜鸟javascript基础资料整理2
2010/12/06 Javascript
随鼠标上下滚动的jquery代码
2013/12/05 Javascript
js验证输入是否为手机号码或电话号码示例
2013/12/30 Javascript
jQuery中next()方法用法实例
2015/01/07 Javascript
Javascript中的方法和匿名方法实例详解
2015/06/13 Javascript
JavaScript判断FileUpload控件上传文件类型
2015/09/28 Javascript
JavaScript Date对象详解
2016/03/01 Javascript
JavaScript实现各种排序的代码详解
2017/08/28 Javascript
解决angularjs前后端分离调用接口传递中文时中文乱码的问题
2018/08/13 Javascript
如何使用 vue + d3 画一棵树
2018/12/03 Javascript
vue文件运行的方法教学
2019/02/12 Javascript
微信小程序HTTP接口请求封装的实现
2019/02/21 Javascript
微信小程序多列表渲染数据开关互不影响的实现
2020/06/05 Javascript
在vue中使用el-tab-pane v-show/v-if无效的解决
2020/08/03 Javascript
[06:16]第十四期-国士无双绝地翻盘之撼地神牛
2014/06/24 DOTA
[00:44]华丽开场!DOTA2勇士令状带来全新对阵画面
2019/05/15 DOTA
Python实现list反转实例汇总
2014/11/11 Python
给Python中的MySQLdb模块添加超时功能的教程
2015/05/05 Python
flask中使用蓝图将路由分开写在不同文件实例解析
2018/01/19 Python
python学习笔记--将python源文件打包成exe文件(pyinstaller)
2018/05/26 Python
使用pycharm设置控制台不换行的操作方法
2019/01/19 Python
Python3删除排序数组中重复项的方法分析
2019/01/31 Python
Python面向对象总结及类与正则表达式详解
2019/04/18 Python
利用python求积分的实例
2019/07/03 Python
Django ORM 查询管理器源码解析
2019/08/05 Python
Python流程控制 while循环实现解析
2019/09/02 Python
CSS3实现超酷的黑猫警长首页
2016/04/26 HTML / CSS
Dr. Martens马汀博士德国官网:马丁靴鼻祖
2019/12/26 全球购物
大学生旷课检讨书
2014/01/22 职场文书
青年教师典范事迹材料
2014/01/31 职场文书
2014党员整改措施思想汇报
2014/10/07 职场文书
2015年保洁工作总结范文
2015/04/28 职场文书