PHP-ThinkPHP中的表单令牌是啥原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP-ThinkPHP中的表单令牌是啥原理相关的知识,希望对你有一定的参考价值。

你说的是token吧
有效防止重复提交,以及跨站伪造请求
Token,就是令牌,最大的特点就是随机性,不可预测。一般黑客或软件无法猜测出来。
Token一般用在两个地方——防止表单重复提交、anti csrf攻击(跨站点请求伪造)。
原理上都是通过session token来实现的。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。
然后,如果应用于“anti csrf攻击”,则服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。
纯手打,望采纳
参考技术A

thinlphp框架项目中开启表单令牌,要在配置文件中做如下配置

array(
    // 是否开启令牌验证
    'TOKEN_ON' => true,
    // 令牌验证的表单隐藏字段名称
    'TOKEN_NAME' => '__hash__',
    //令牌哈希验证规则 默认为MD5
    'TOKEN_TYPE' => 'md5',
    //令牌验证出错后是否重置令牌 默认为true
    'TOKEN_RESET' => true
);

编辑数据

$table = D('table');
if (!$table->create()) 
    exit($this->error($table->getError()));

TP框架中Model.class.php中的create方法

/**
 * 创建数据对象
 * @access public
 * @param mixed $data 创建数据
 * @param string $type 状态
 * @return mixed
 */
function create($data = '', $type = '')

    // 表单令牌验证
    if (!$this->autoCheckToken($data)) 
        $this->error = L('_TOKEN_ERROR_');
        return false;
    

当autoCheckToken方法检测失败时会报错

// 自动表单令牌验证
function autoCheckToken($data)
  
    // 支持使用token(false) 关闭令牌验证
    // 如果在Action写了D方法,但没有对应的Model文件,那么$this->options为空
    if (isset($this->options['token']) && !$this->options['token']) return true;
    if (C('TOKEN_ON')) 
        $name = C('TOKEN_NAME');
        if (!isset($data[$name]) || !isset($_SESSION[$name]))  // 令牌数据无效
            return false;
            
        // 令牌验证
        list($key, $value) = explode('_', $data[$name]);
        if ($value && $_SESSION[$name][$key] === $value)  // 防止重复提交
            unset($_SESSION[$name][$key]); // 验证完成销毁session
            return true;
            
        // 开启TOKEN重置
        if (C('TOKEN_RESET')) unset($_SESSION[$name][$key]);
        return false;
    
    return true;

$_SESSION[$name]这个seesion变量,从生成令牌时说起,定位TokenBuildBehavior.class.php文件

// 创建表单令牌
function buildToken()

    $tokenName = C('TOKEN_NAME');
    $tokenType = C('TOKEN_TYPE');
    if (!isset($_SESSION[$tokenName])) 
        $_SESSION[$tokenName] = array();
      
    // 标识当前页面唯一性
    $tokenKey = md5($_SERVER['REQUEST_URI']);
    if (isset($_SESSION[$tokenName][$tokenKey])) 
        // 相同页面不重复生成session
        $tokenValue = $_SESSION[$tokenName][$tokenKey];
     else 
        $tokenValue = $tokenType(microtime(TRUE));
        $_SESSION[$tokenName][$tokenKey] = $tokenValue;
    
    $token = '<input type="hidden" name="' . $tokenName . '" value="' . $tokenKey . '_' . $tokenValue . '" />';
    return $token;

这段代码主要是在TP开启表单验证的情况下,以TOKEN_NAME和当前URI的md5为健生成令牌值,

再在用户提交表单时,先验证下是否存在该session,没有则返回false,有则紧接着和表单字段TOKEN_NAME验证下,

如果一致先删除此session(作用时避免下次提交出先表单令牌错误),返回ture,否则返回false。

参考技术B

这是thinkphp5的表单令牌生成源码,可以看到是加密了时间戳

public function token($name = '__token__', $type = 'md5')
    
        $type  = is_callable($type) ? $type : 'md5';
        $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']);
        if ($this->isAjax()) 
            header($name . ': ' . $token);
        
        Session::set($name, $token);
        return $token;
    

参考技术C 生成一个token值,用session缓存起来,这个过程是在打开填写表单的页面时就生成了,然后我们填写完数据是提交到php页面,此时的token值会和之前缓存起来的值进行对比,如果不一样就会报错。 参考技术D 它是用来防止表单非法提交,令牌就是为每个表单生成的唯一ID用来验证安全性、是不是合法的表单提交。本回答被提问者和网友采纳

以上是关于PHP-ThinkPHP中的表单令牌是啥原理的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 中的 FCM 令牌是啥?

jwt 令牌中的“gty”声明是啥意思?

OAuth 2 中的不记名令牌和 token_type 是啥?

表单提交中的重复问题(表单令牌验证)

Zend Form - 一页中的多个表单和(CSRF)令牌验证

币圈令牌是啥意思