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中在数据库中保存Checkbox数据(1)
Oct 09 PHP
PHP数据库开发知多少
Oct 09 PHP
php的计数器程序
Oct 09 PHP
神盾加密解密教程(一)PHP变量可用字符
May 28 PHP
PHP常量使用的几个需要注意的地方(谨慎使用PHP中的常量)
Sep 12 PHP
PHP获取远程图片并保存到本地的方法
May 12 PHP
PHP和MySql中32位和64位的整形范围是多少
Feb 18 PHP
php微信高级接口群发 多客服
Jun 23 PHP
一个简单安全的PHP验证码类、PHP验证码
Sep 24 PHP
php json相关函数用法示例
Mar 28 PHP
PHP实现求两个字符串最长公共子串的方法示例
Nov 17 PHP
PHP经典设计模式之依赖注入定义与用法详解
May 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
PHPCMS手机站伪静态设置详细教程
2017/02/06 PHP
用Javascript做flash做的事..才完成的一个类.Auntion Action var 0.1
2007/02/23 Javascript
Ajax执行顺序流程及回调问题分析
2012/12/10 Javascript
JQuery中关于jquery.js与jquery.min.js的比较探讨
2013/05/15 Javascript
javascript自然分类法算法实现代码
2013/10/11 Javascript
给文字加上着重号的JS代码
2013/11/12 Javascript
深入浅析JavaScript字符串操作方法 slice、substr、substring及其IE兼容性
2015/12/16 Javascript
微信QQ的二维码登录原理js代码解析
2016/06/23 Javascript
jquery动态添加文本并获取值的方法
2016/10/12 Javascript
基于nodejs res.end和res.send的区别
2018/05/14 NodeJs
解决使用layui对select append元素无效或者未及时更新的问题
2019/09/18 Javascript
jQuery实现全选、反选和不选功能的方法详解
2019/12/04 jQuery
vue Element左侧无限级菜单实现
2020/06/10 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
[51:26]VP vs VG 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
使用BeautifulSoup爬虫程序获取百度搜索结果的标题和url示例
2014/01/19 Python
离线安装Pyecharts的步骤以及依赖包流程
2020/04/23 Python
python之virtualenv的简单使用方法(必看篇)
2017/11/25 Python
Python3 获取一大段文本之间两个关键字之间的内容方法
2018/10/11 Python
浅谈Python 递归算法指归
2019/08/22 Python
python3 pillow模块实现简单验证码
2019/10/31 Python
在Django中预防CSRF攻击的操作
2020/03/13 Python
Python读取yaml文件的详细教程
2020/07/21 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
使用HTML5 Canvas为图片填充颜色和纹理的教程
2016/03/21 HTML / CSS
Godiva巧克力英国官网:比利时歌帝梵巧克力
2018/08/28 全球购物
Carmen Sol官网:购买果冻鞋、手袋和配件
2021/01/01 全球购物
物理教育专业毕业生推荐信
2013/11/03 职场文书
幼儿园教师工作制度
2014/01/22 职场文书
幼儿园教学管理制度
2014/02/04 职场文书
八项规定整改方案
2014/02/21 职场文书
节水标语大全
2014/06/11 职场文书
学党史心得体会
2014/09/05 职场文书
学生保证书格式
2015/02/27 职场文书
2015年建党94周年演讲稿
2015/03/19 职场文书
nginx+lua单机上万并发的实现
2021/05/31 Servers