Codeigniter CSRF过期令牌

4

在我的 CodeIgniter Ajax 应用程序中,如果用户的会话已过期并且他们提交一个 Ajax 表单,则由于 CSRF 令牌已过期,服务器会返回 500 错误... 我如何让服务器返回 401 错误,以便我至少可以处理错误并将用户重定向到登录表单?

1个回答

2
使用输出类(Output class)。来自用户指南:

$this->output->set_status_header(code, 'text');

允许您手动设置服务器状态标头。例如:

$this->output->set_status_header('401');
// Sets the header as: Unauthorized
我正准备建议扩展Security类并覆盖生成CSRF错误的函数:
/**
 * Show CSRF Error
 *
 * @return  void
 */
public function csrf_show_error()
{
    //show_error('The action you have requested is not allowed.');

    // Set 401 header instead of the default 500
    show_error('The action you have requested is not allowed.', 401);
}

...但这并不总是正确的 - 更重要的是,当令牌被提交时,我认为您不需要这样做。在验证令牌之前,您应该已经发送了未经授权的标头

从您的评论中:

问题不在于csrf令牌和会话直接相关,而是它们的默认过期时间相同。因此,如果用户在一段时间内没有刷新浏览器,然后刷新页面,CI将更新会话和csrf令牌...但是由于ajax无法刷新令牌,因此它只返回500错误。

如果这是唯一阻止您在CSRF令牌之前验证会话的事情,请尝试将会话令牌的过期时间比令牌早10秒。如果请求未经授权,则验证令牌毫无意义。


有趣的是,我实际上并不知道令牌在CI执行中如此早地被验证。你尝试过将其硬编码到system/Security.php中的csrf_show_error()函数中以确保它否正常工作吗? - Wesley Murch
所以我刚刚尝试在核心文件夹中创建一个MY_Output.php,并将401头放置在构造函数中,似乎确实可以在csrf验证之前正确发送头文件...但这真的没有帮助,因为它超出了我的控制器范围,我似乎找不到一个变量来用于条件设置头文件...而且它只是感觉像一个hack。 - websiteguru
csrf_show_error() 似乎只设置错误信息,而不是标头。 - websiteguru
我的错误,实际上是在构造Input类时调用了_sanitize_globals()函数,在这个函数中是唯一调用csrf_verify()的地方。希望这可以帮到你,我已经更新了答案但我现在没有更多的想法了。 - Wesley Murch
实际上我意识到了这个问题:CI首先验证CSRF令牌。我想要的是在处理Ajax请求之前查看用户会话是否仍然活动,但是在我能够达到那里之前,CI就已经抛出了CSRF错误。顺序是相反的。 - websiteguru
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,