将令牌置于URL安全中,以防止PHP应用程序中的CSRF攻击


is putting token in URL secure to prevent CSRF attacks in PHP applications?

我想使用令牌来防止CSRF攻击我的网站(用PHP编写)。我在各种形式中使用过它,效果很好。但是logout link不是表单;它只是一个超链接。
如果我像这样将令牌放入查询字符串中,是否安全?

<a href="logout.php?token=9ae328eea8a72172a2426131a6a41adb">Logout</a>

如果它有任何问题,你的建议和解决方案是什么?

是的,如果 CSRF令牌是'不可猜的'并且经过验证:在两种情况下方法是相同的。

来自维基百科的跨站点请求伪造-预防:

网站有各种CSRF对策可用。在所有表单提交和副作用url 中要求一个秘密的、特定于用户的令牌可以防止CSRF;攻击者的站点无法在其提交的内容中放入正确的令牌。

无论标记来自表单值还是查询字符串参数1。通过在表单中包含令牌来防止CSRF的方法适用于(并且对)超链接2有效。


1可以拦截URL的MitM/代理也可以很容易地拦截HTML表单。这超出了标准CSRF攻击或此类缓解的范围。在这种情况下,CSRF令牌值是"可知的",系统是不安全的。

2这里假设令牌是每个用户(并且对时间敏感)的值。在大多数情况下,会话ID的简单HMAC哈希应该足够了。

我认为在GET请求中使用csrf令牌的主要缺点之一是不合格的用户很容易通过复制带有令牌的链接并将其粘贴到一些公共内容(如评论/帖子等)中来泄露他的令牌。此外,GET查询参数包括csrf令牌,通常由HTTP服务器/代理记录,它引入了另一种风险。

因此,我建议您使用以下内容实现csrf安全链接:

<form name="logout" action="logout.php" method="post">
<input type="hidden" name="token" value="9ae328eea8a72172a2426131a6a41adb"/>
</form>
...
<a href="/nojs.html" onclick="document.logout.submit(); return false">Logout</a>

其他人提出了一些好的观点。我加上这个答案来补充他们的。 始终过滤和验证您的查询字符串名称/值对

给定:您有一个数据库,您希望创建一个链接来帮助动态获取(但不更改)用户可以链接到的内容。示例:新闻文章、案例研究、公共用户配置文件。

需求:使用查询字符串并使用令牌阻止CSRF。

CSRF令牌的目的之一是帮助验证传入的HTTP请求是从您的域提供服务的页面生成的(无论会话是否正在进行)。会话令牌是一个单独的野兽)。当您使用多个防御向量时,CSRF令牌效果最佳。

比较:检查提交的令牌是否与会话中的令牌匹配。

Time:可以指定一个令牌只在未来的一段时间内有效。

public function setFormToken()
{
    $token = $this->cipher->getFormToken();  //Some hashing algorithm.
    $this->formToken   = $token; //In this example, used to insert the token into HTML.
    $_SESSION['token'] = $token; //Save the token for comparison upon form submission / HTTP query string processing.
    $_SESSION['tokenExpireTime'] = time() + (60 * FORM_TOKEN_EXPIRE_MINUTES); //This is just an abstract example.
    return;
}

然后,除了将提交的令牌与会话中的令牌进行比较外,还要验证提交周期是否仍然有效。

private function hasTokenTimeLeft()
{
    if(isset($_SESSION['tokenExpireTime']) && (time() < $_SESSION['tokenExpireTime']))
    {
        return true;
    }
    throw new SecurityException("Token time has expired for this POST request.", 911);
}

Sessions:如果会话已经过期,或者不存在,对您的内容的错误HTTP请求应该失败。

请求信息:对于HTTP POST请求,一些尝试检查令牌,用户代理和IP是否与原始HTTP GET请求匹配(这意味着在响应GET请求之前将其存储在会话中)。如前所述,

查询字符串可以被缓存。无论如何,如果这些数据应该是公开的,那就没有问题了。想想某人在电子商务网站上为产品添加书签。

你要问自己的是"我是否能够随时随地通过这个带有查询字符串的链接访问这个内容?"如果是,则不要使用真实的后端随机生成的CSRF令牌。想象一下,你正在通过口口相传的方式竞选公职,人们通过电子邮件向他们的朋友和家人发送链接(好吧,这是不好的做法)。在这种情况下,您永远不希望触发"绊线"并导致失败情况。如果总是需要在后端生成一个新的令牌,那么通过电子邮件发送您的链接将不起作用。

如果您不应该能够从安全上下文之外获得内容(即,在登录之前),那么您可以自由地采取任何必要的措施来使用查询字符串来加强您的CSRF令牌策略。

你的注销代码段就是一个很好的例子。

<a href="logout.php?token=9ae328eea8a72172a2426131a6a41adb">Logout</a>

安全上下文之外的任何人都不能使用注销功能。如果有人通过电子邮件发送这个链接,你想要"绊线"!显然,会话被集成到这个解决方案中(当用户使用页面时,令牌必须存储在某个地方)。会话持续时间和注销应该仔细管理,我说你做得很好。

加密:唯一可以做得更好的是加密查询字符串的哈希/令牌,然后解密并在提交时验证它。此外,您可以将令牌拆分成几个部分,将这些部分混合在一起,并基本上使用一些通过晦涩字符串技术的安全性来使您的CSRF令牌更具弹性。