【问题标题】:php token match does not workphp令牌匹配不起作用
【发布时间】:2017-05-11 23:42:01
【问题描述】:

我正在做表单验证器(使用令牌)。 页面基于 smarty。所以在类文章中我有以下功能:

public static function getToken(){
		self::$token = md5(uniqid(rand(), TRUE));
		$_SESSION['token'] = self::$token;
	}

然后在 .tpl 文件中我插入了这样的值:

<input type="hidden" name="token" value="{Articles::$token}">

表单提交后,检查在 index.php 中运行:

if(isset($_POST['token']) && $_POST['token'] == $_SESSION['token']){
	Articles::addComment($item, $_POST['name'], $_POST['email'], $_POST['comment']);
}

问题是我得到了不同的令牌。例如,我回显了$_SESSION['token'] 并与表单中的值进行了比较(查看源代码)。 同样在提交之后,我尝试回显($_SESSION ['token']$_POST ['token]) 这两个值,它们也不同。显然,表单没有提交。

【问题讨论】:

  • 为什么它们应该是一样的?在第二个请求 getToken 生成新令牌并在 SESSION 中覆盖了一个,这当然与第一个不同
  • @Lashane,请您详细说明一下。我不遵循它被视为第二个请求的地方。我只调用了一次函数。
  • 当您发布表单时 - 这是第二次请求,您肯定会第二次调用 getToken
  • 您能推荐一些东西吗?我对此很陌生。
  • @Benua 如果在第二次请求时生成新令牌,请使用简单的条件 if(empty($_SESSION['token'])) { getToken()}

标签: php smarty token


【解决方案1】:

CSRF 令牌不需要为用户进行 1:1 映射。如果一个页面上有多个表单怎么办?如果用户打开了多个浏览器窗口怎么办?

定义一些东西来存储0..n 令牌,在它们上设置一个相当短的有效期,并[可选地]定义它们的有效性什么。例如:

class Token {
    protected $id, $expiry;

    public function __construct($expiry=300, $id=NULL) {
        $this->expiry = time() + $expiry;
        if( is_null($id) ) {
            // actual secure ID generation.
            $this->id = bin2hex(random_bytes(32));
        } else {
            $this->id = $id;
        }
    }

    public function getID() {
        return $id;
    }

    public function isValid() {
        return time() < $expiry;
    }
}

class YourApp {
    public function newToken() {
        $token = new Token();
        $_SESSION['tokens'][$token->getID()] = $token;
        return $token
    }

    public function checkToken($token_id) {
        if( key_exists($token_id, $_SESSION['tokens']) ) {
            $cur = $_SESSION['tokens'][$token_id];
            unset($_SESSION['tokens'][$token_id]; // single use only!
            return $cur->isValid();
        } else {
            return false;
        }
    }

    public function flushOldTokens() {
        $_SESSION['tokens'] = array_filter(
            $_SESSION['tokens'],
            function($t){return $t->isValid();}
        );
    }
}

【讨论】:

  • "如果页面上有多个表单怎么办?" --- 那么,然后呢?拥有一个不会过期且非一次性使用的 csrf 令牌有什么问题?
  • 如果令牌可以被截获 - 拥有多个令牌并不能防止任何事情:一旦令牌被盗 - 它可以很快被使用。 (并且合法用户的请求将失败)。所以,你的建议没有解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-07
  • 2020-11-09
  • 2019-01-15
  • 2016-10-24
  • 1970-01-01
相关资源
最近更新 更多