如何防止 PHP、csrf、xsrf 中的表单重放/中间人攻击

Posted

技术标签:

【中文标题】如何防止 PHP、csrf、xsrf 中的表单重放/中间人攻击【英文标题】:How to prevent form replay/man-in-the-middle attack in PHP, csrf, xsrf 【发布时间】:2010-12-05 10:20:13 【问题描述】:

我有一个网络表单,我正在使用 php。我知道表单可以被操纵(我相信它被称为重放攻击或中间人攻击)。所以我想使用一些真实性令牌作为隐藏字段。

我知道的威胁可能性是:

攻击者劫持了合法用户的表单(我认为这是中间人攻击) 合法用户本身就是攻击者:他获取表单,读取令牌,但使用它发送危险数据(我认为这是重放攻击)

在我回答问题之前,如果我到目前为止所说的任何内容不正确,请纠正我,因为我的理解可能有缺陷。

现在问题:

生成此令牌以使没有它的表单被拒绝的最佳做法是什么(例如,加盐?)。 人们如何确保令牌不会被重放。

基于cmets的新小问题:

会话劫持与中间人攻击相同吗?

【问题讨论】:

出于某种原因,我认为您使此过程过于复杂。为什么数据验证还不够?您是否担心有人会提交被劫持的表单数据?它改变了吗?还是登录类型的表格? (可以通过 SSL 完成以消除中间人攻击)。 也许我过于复杂了,我不知道。当我读到它时,它似乎很复杂,漏洞太多。但是问题 1 仍然有效,因为我不知道生成该令牌的最佳做法是什么:) 问题 2(关于重放令牌的问题)是否有效,我也希望能够理解。 是的,条款有误。 Chris 描述的是会话劫持和 XSRF。 SSL 防止第一个,网站设计防止第二个。 SSL 是一个很大的帮助,因为它可以隐藏您的 cookie 以防被嗅探。但它不会阻止你的 cookie 被 XSS 窃取,所以它不是灵丹妙药。 而且,不,会话劫持不是中间人。会话劫持通过传递您的会话 cookie 来冒充您。 Man-in-the-middle 是一种基于告诉每一方它是另一方的一般攻击类型。它可以用于会话劫持,但比这更通用。 【参考方案1】:

您在标题中提到了 CSRF,但在您的问题中并没有真正涵盖它。

你可以详细阅读它online,但 CSRF 基本上是一种攻击,它让合法用户在不知不觉中提交到网站。例如,如果 SO 不能防止此类攻击,我可以制作一个表单,当您单击我的这种不良表单时,会导致您的 SO 个人资料信息发生更改,并期待其他事情发生(“赢一百万美元!点击这里!!”)。此表单将使用您的浏览器 cookie 向 SO 验证您的身份,并使 SO 看起来您正在合法地提交对您的个人资料的更新。

为了防止这种情况,你真的想做几件事:

确保 GET 不会导致更新(例如,不要使用 GET 上的查询参数将新的状态更新发布到用户的配置文件) 确保所有 POST 都附有一个隐藏字段,让您可以验证表单是由您的服务生成的,而不是由其他人生成的,并且它是为预期用户生成的。所以这个隐藏字段必须由服务器每次发送表单的 html 时生成,并且对于该会话的该用户来说应该是唯一的。

第二项的替代方法是检查引用者是否始终是您的站点或您期望 POST 来自的站点。对于非 HTTPS 网站,我不鼓励这样做,因为某些浏览器/网络硬件会去除引荐来源网址,并且引荐来源网址的存在并不总是可靠的。

【讨论】:

我只在标题中提到了 CSRF,因为我觉得它与表单真实性令牌有某种关系,只是不确定如何。 绝对是——希望我的回答足够清楚地说明如何/为什么。 是的,现在越来越清楚了,感谢您的回答。我投了赞成票 引荐来源网址可以被欺骗,iirc【参考方案2】:

用于生成令牌的方法不是很重要。 重要的是令牌只能使用一次。 在用户会话中保留为用户生成的令牌列表。如果用户提交表单并且提交的令牌不在会话中,您可以拒绝该表单。

防范中间人有点困难。我见过的一种常见技术是在哈希函数中包含所有隐藏的表单字段来生成令牌,然后根据已知的隐藏字段重新生成令牌。但是,这只能防止隐藏场操纵,这可能不是中间人的最终目标。

当用户成功提交带有令牌的表单时,从会话中删除令牌,因此该提交的任何重放都将失败。但是,只需用户再次请求表单以生成另一个令牌。然后可以在随后的自动攻击中使用该新令牌。 换句话说,表单令牌对 CSRF 很有用,但对自动重放和中间人攻击不是很有效。

同样,您需要调整您的应用程序,使其不需要在表单上使用用户的后退按钮。如果他们的提交有问题,您需要将表单返回给用户并填写他们的数据。如果用户点击她的后退按钮来纠正错误,她的提交将由于现在无效而失败令牌。

另外,坦率地说,当您需要担心请求重放和中间人攻击时,您的用户连接已经受到威胁,您可能无法采取任何措施来减轻任何损害。单独使用 SSL 就足以防止 MITM 和重放,如果您担心它,您将在 SSL 下运行...

【讨论】:

或者,简而言之:使用 SSL。 不,SSL 不会做任何事情来防止 XSRF 攻击,因此“仅使用 SSL”并没有涵盖它。 它确实可以防止会话劫持,这是 Chris 担心的另一个问题。 XSRF 并没有那么大的风险,除非你违反了允许 get 改变事物所概述的规则。 如果攻击者控制了用户的浏览器,那么就没有办法保护用户。攻击者可以绕过浏览器中实现的所有保护。【参考方案3】:

要生成该令牌,这是我使用的一个似乎效果不错的策略。

将 cookie 设置为随机值(使用常用技巧在服务器上生成)并根据需要将其设置为过期。 使用表单提供页面时,嵌入一个隐藏字段,其值等于此 cookie 的值。 在处理帖子时,验证该字段是否存在,并且该值与用户的 cookie 匹配

【讨论】:

You cannot use cookies to protect against CSRF【参考方案4】:

csrf-magic 是一个很棒的 CSRF 令牌类,它会自动将它们放入您的页面中

http://csrf.htmlpurifier.org/

"csrf-magic 使用 PHP 的输出缓冲功能来动态重写文档中的表单和脚本。它还会拦截 POST 请求并检查它们的令牌(使用了各种算法;有些生成随机数,有些生成用户特定的令牌)。这意味着,对于带有表单的传统网站,您可以将 csrf-magic 放入您的应用程序中,然后忘记它!”

【讨论】:

以上是关于如何防止 PHP、csrf、xsrf 中的表单重放/中间人攻击的主要内容,如果未能解决你的问题,请参考以下文章

第二百七十一节,Tornado框架-CSRF防止跨站post请求伪造

PHP-Yii框架下提交表单form防止csrf攻击

Angular 和 PHP JWT 和 CSRF (XSRF) Cookie

如何在 SAST Checkmarx 之后解决 API 控制器中的 XSRF 跨站请求伪造 (CSRF)

CSRF/XSRF (跨站请求伪造)

防止 asp.net Web 表单中的跨站点请求伪造 (csrf) 攻击