在基于 AJAX 的应用程序中使用令牌防止 CSRF

Posted

技术标签:

【中文标题】在基于 AJAX 的应用程序中使用令牌防止 CSRF【英文标题】:Preventing CSRF with tokens in a AJAX based application 【发布时间】:2014-06-20 07:27:24 【问题描述】:

我正在使用令牌来防止我的应用程序中的 CSRF 攻击。但是这个应用程序是单页的,并且大量基于 AJAX,所以我需要找到一种方法来为单页中的 N 个操作提供有效的令牌:

例如一个文档片段加载了 3 个可能的操作,每个操作都需要一个令牌才能正常工作,但服务器端一次只有一个有效令牌...

由于每个令牌都只是一个encrypted nonce(该值不是基于特定形式),因此我提出了通过以下方式自动为每个操作分配令牌的想法:

    App 拦截 AJAX 调用,并检查是否为敏感操作(即删除用户) 在操作继续之前向服务器请求令牌 生成令牌,然后添加到操作请求中 自请求包含有效令牌后执行的操作 对通过 AJAX 执行的任何后续操作执行相同操作

我认为该方法不够有效,因为攻击者可以使用与我的应用完全相同的脚本(检索令牌并附加到请求)。

如何改进我的方法以有效抵御 CSRF 攻击?

附加信息:我的后端环境是 php/Phalcon,令牌是 generated using Phalcon。

【问题讨论】:

假设您使用会话登录并且不允许未登录的用户删除用户,攻击者将如何登录并执行请求?如果它是对您的真正 CSRF 攻击以删除用户,那么攻击者将如何知道您的 nonce?如果它是一个公共 API,是的,他们可以先抓取您的页面,然后获取随机数,然后执行请求,您无法 100% 停止,您可以添加层但仍然可以。您甚至可以使用带有与用户相关的参数的加密字符串来代替 nonce,但通常它是矫枉过正的。 “每个动作都需要一个令牌才能正常工作,但服务器端有时只有一个有效令牌......” - 然后更改:为 每一个可能的动作。 【参考方案1】:

比仅对 AJAX 使用令牌更简单的方法可能是检查只能出现在来自您自己域的 AJAX 请求中的标头。

两个选项是:

Checking the Origin Header Checking the X-Requested-With header

Origin 标头也可用于正常的 html 表单提交,您将在表单提交处理之前验证它是否包含您自己网站的 URL。

如果您决定检查 X-Requested-With 标头,则需要确保将其添加到每个 AJAX 请求客户端(默认情况下,JQuery 将执行此操作)。由于此标头不能跨域发送(未经您的服务器首先同意浏览器),检查它是否存在并设置为您自己的值(例如“XMLHttpRequest”)将验证请求不是 CSRF 攻击。

【讨论】:

@IanBytchek 整个 wiki 都充满了必须知道的信息 只剩下决定什么是必须知道的:P @SilverlightFox,略过,早期的浏览器不支持 CORS。那么,这些技术大多只适用于 AJAX 请求,对吧?如果我编译一个有效的请求,我认为这可以使用 curl 绕过? 我想我明白了。好书——***.com/questions/4850702/… @IanBytchek 是的,Origin 标头只会出现在支持 CORS 的浏览器中,但对 X-Requested-With 的限制应该也适用于 pre-CORS 跨域请求.警告:结果可能因浏览器而异。是的,它们可以被curl 欺骗,但在这种情况下,攻击者不会让浏览器注入受害者的 cookie(我怀疑你现在已经知道了)。【参考方案2】:

不久前我不得不处理类似的事情。使用 ajax 请求 nonce 是一个非常糟糕的主意——恕我直言,如果攻击者可以简单地生成它而不重新加载页面,它会使拥有它们的全部意义无效。我最终实现了以下内容:

    Nonce 模块(操作的大脑),用于处理 nonce 的创建、销毁、验证和层次结构(例如,具有多个输入的一页的子 nonce)。 每当呈现表单/特定输入时,都会生成随机数并将其存储在具有过期时间戳的会话中。 当用户完成操作/表单/页面时,具有其层次结构的随机数被破坏。如果操作是重复的,请求可能会返回一个新的随机数。 在生成新的随机数时,会检查旧的随机数并删除过期的随机数。

它的主要问题是决定 nonce 何时到期并清理它们,因为它们就像类固醇上的细菌一样生长。您不希望用户提交打开了一个小时的表单并因为 nonce 已过期/删除而被卡住。在这些情况下,您可以使用重新生成的随机数返回“超时,请重试”消息,因此根据以下请求,一切都会通过。

如前所述,没有什么是 100% 防弹的,而且在大多数情况下是矫枉过正。我认为这种方法在偏执和不浪费几天时间之间取得了很好的平衡。对我有很大帮助吗?与显着提高安全性相比,它对它的偏执做得更多。

从逻辑上思考,在这些情况下您能做的最好的事情就是分析请求背后的行为,并在它们可疑时将其暂停。例如,来自一个 ip 的每分钟 20 个请求,跟踪鼠标/键盘,确保它们在请求之间处于活动状态。换句话说,确保请求不是自动化的,而不是确保它们带有有效的随机数。

【讨论】:

您的解决方案中是否考虑过 XSS 攻击? 任务是防止不需要的数据被随意提交到服务器。这是一个非常通用的解决方案,它不是 100% 防弹的,但它确实阻止了大多数自动表单提交。 XSS 是一个非常不同的故事,我完全看不出使用令牌如何帮助解决它:) 只能通过使用常识来防止它,而不是深夜工作,并测试你的代码是否存在漏洞。

以上是关于在基于 AJAX 的应用程序中使用令牌防止 CSRF的主要内容,如果未能解决你的问题,请参考以下文章

用于ajax调用的spring security csrf保护

如果我使用基于令牌的身份验证,我应该如何加载图像

如何使用被盗令牌防止 Rest Web 服务身份验证

Django 项目中基于 CSRF 令牌 AJAX 的帖子

这是为了防止使用 PHP 和 Ajax 的 CSRF 所需要做的吗?

防止在 asp.net 5 (vNext) 中对预检 OPTIONS 请求进行基于令牌的授权