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 相关文章推荐
简单示例AJAX结合PHP代码实现登录效果代码
Jul 25 PHP
微盾PHP脚本加密专家php解密算法
Sep 13 PHP
教你如何使用php session
Oct 28 PHP
PHP生成等比缩略图类和自定义函数分享
Jun 25 PHP
php异常处理方法实例汇总
Jun 24 PHP
Django中的cookie与session操作实例代码
Aug 17 PHP
php curl批处理实现可控并发异步操作示例
May 09 PHP
php+Ajax处理xml与json格式数据的方法示例
Mar 04 PHP
PHP使用Session实现上传进度功能详解
Aug 06 PHP
Yii框架连表查询操作示例
Sep 06 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
Feb 21 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 fsockopen写的HTTP下载的类
2007/02/22 PHP
php db类库进行数据库操作
2009/03/19 PHP
ThinkPHP应用模式扩展详解
2014/07/16 PHP
php在linux下检测mysql同步状态的方法
2015/01/15 PHP
详解WordPress中给链接添加查询字符串的方法
2015/12/18 PHP
php array_pop 删除数组最后一个元素实例
2016/11/02 PHP
PHP curl 或 file_get_contents 获取需要授权页面的方法
2017/05/05 PHP
jQuery timers计时器简单应用说明
2010/10/28 Javascript
jquery $.fn $.fx是什么意思有什么用
2013/11/04 Javascript
Js 去掉字符串中的空格(实现代码)
2013/11/19 Javascript
非常漂亮的JS+CSS图片幻灯切换特效
2013/11/20 Javascript
JavaScript操作Cookie方法实例分析
2015/05/27 Javascript
Bootstrap基本组件学习笔记之进度条(15)
2016/12/08 Javascript
微信小程序中使元素占满整个屏幕高度实现方法
2016/12/14 Javascript
详解如何让Express支持async/await
2017/10/09 Javascript
AngularJS的$location使用方法详解
2017/10/19 Javascript
JavaScript EventEmitter 背后的秘密 完整版
2018/03/29 Javascript
详解Angular5路由传值方式及其相关问题
2018/04/28 Javascript
Koa2微信公众号开发之本地开发调试环境搭建
2018/05/16 Javascript
vue动画打包后失效问题的解决方法
2018/09/18 Javascript
[01:56]《DOTA2》中文配音CG
2013/04/22 DOTA
学习python (2)
2006/10/31 Python
Python3.x中自定义比较函数
2015/04/24 Python
Python中urllib+urllib2+cookielib模块编写爬虫实战
2016/01/20 Python
Python中join函数简单代码示例
2018/01/09 Python
详解KMP算法以及python如何实现
2020/09/18 Python
python 解决函数返回return的问题
2020/12/05 Python
Groupon荷兰官方网站:高达70%的折扣
2019/11/01 全球购物
托管代码(Managed Code)和非托管代码(Unmanaged Code)有什么区别
2014/09/29 面试题
老师给学生的表扬信
2014/01/17 职场文书
优秀毕业生就业推荐信
2014/05/22 职场文书
沙滩主题婚礼活动策划方案
2014/09/15 职场文书
山东省召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
2014年个人工作总结报告
2014/11/27 职场文书
浅析Redis Sentinel 与 Redis Cluster
2021/06/24 Redis
MySQL中dd::columns表结构转table过程及应用详解
2022/09/23 MySQL