在 Python REST API 中实现 CSRF 保护

Posted

技术标签:

【中文标题】在 Python REST API 中实现 CSRF 保护【英文标题】:Implementing CSRF protection in a Python REST API 【发布时间】:2016-05-09 00:20:08 【问题描述】:

使用 JWT 编写带有 Pyramid/Cornice 的 REST API 进行身份验证,我将不得不实现一些 CSRF 保护。 彻底阅读了该主题后,我理解了这个问题,但我对实现它的最佳方法感到非常困惑,考虑到所有可能的攻击媒介,这有点棘手。

由于此 API 允许访问敏感数据并将作为开源软件发布,因此它需要独立的保护。它将在具有不受信任的子域的环境中使用,我不能依赖用户遵循安全准则。

对于我的无状态服务,我可以使用“Double Submit Cookies”或“Encrypted Token Pattern”方法。

双重提交 Cookies

为了防止"cookie tossing",Double Submit 方法中的令牌需要是可验证的。 MiTM attacks 是一个额外的威胁,我希望通过仅强制使用 HTTPS-cookie 来充分缓解。

为了获得一个攻击者不容易猜到和复制的可验证令牌,我想像这样的哈希令牌应该可以工作:

pbkdf2_sha256.encrypt($userid + $expire + $mycsrfsecret, salt=$salt)

“exp”是来自 JWT 的过期值。 JWT 将与 CSRF-cookie 一起发布,并且“exp”可以被服务器读取,这增加了一些额外的保护,因为它是可变的并且攻击者不知道它(可能是多余的?)。

根据请求,我可以轻松地将收到的两个令牌相互比较,并使用 pbkdf2_sha256.verify($tokenfromrequest, $userid + $exp + $mycsrfsecret) 将其与 JWT 令牌('Verifiablity')中的值进行比较。

这种方法会遵循推荐的做法吗?

我选择了 pbkdf2 而不是 bcrypt,因为它的验证方法明显更快。

到期时间将设置为 7 天,之后 JWT 和 CSRF 令牌都将通过新登录来更新(它们也将在中间重新登录时更新)。

加密令牌模式

The alternative 是向客户端发送一个字符串,由用户ID、到期时间和随机数组成,并使用服务器端的秘密加密。在请求时,此字符串会被发送,服务器可以对其进行解密并验证用户 ID 和到期时间。

这似乎是更简单的方法,但我不确定如何实现它,我不打算推​​出自己的加密货币,我还没有找到好的例子:

我应该在 Python 中使用什么密码/库?如何进行先加密后 MAC? 如何将令牌保留到其自然到期?我不希望用户每次重新启动浏览器时都必须重新登录。本地存储不是一个安全的地方 - 但别无选择。

【问题讨论】:

加密令牌模式是否保护 xss 攻击或中间人?我认为 csrf 令牌可以保护这件事,我不太确定简单令牌是否可以做到这一点。 @cyan 在到期之前的时间范围内可能会发生重放攻击,但使用 HTTPS,MitM 应该很难获得令牌。对于 XSS,我不确定是否可以访问除不安全的 cookie 或本地存储之外的任何内容,但我也不完全确定加密令牌模式是如何实现的,因此我对持久性提出了疑问。 嗨 Christian - 您最终是否为您的 REST API 实现了 CSRF 解决方案? @Jared - 我用“双重提交 cookie”实现了它,见 github.com/peletiah/goatFS-API/blob/master/goatfs_api/lib/… 【参考方案1】:

使用 JWT 编写带有 Pyramid/Cornice 的 REST API 进行身份验证

虽然我不熟悉这些框架,但我建议您确保 JWT 令牌在不是 cookie 的 HTTP 标头(例如 My-JWT-Token: ... )中传递。那么您不必担心 CSRF 向量。

跨站请求伪造是一个问题,因为浏览器总是倾向于向特定域提交 cookie(通常包含身份验证信息)。浏览器不会自动提交自定义标头,因此您不必担心。

双重提交 Cookies

您的方法过于复杂,您可以简单地使用 GUID。将该 GUID 放入 cookie 中,并将其放入请求的任何其他部分。如果它们相等,则 CSRF 检查通过。您也可以将 GUID 放入 JWT,然后验证 GUID 是否也在 header/body/query 参数中。

加密令牌模式

这几乎就是 JWT 的本质,只需按照建议在标头中传递令牌 ?

回答问题:

我建议hmac 就像import hmac 一样。我不会打扰加密,而只是确保令牌中没有敏感信息。否则 PyCrypto 可能对你有好处。 这就是 cookie 存在的原因,这确实再次引发了 CSRF 问题。如果这是一个硬性要求,那么我建议使用双重提交 cookie 方法。

【讨论】:

以上是关于在 Python REST API 中实现 CSRF 保护的主要内容,如果未能解决你的问题,请参考以下文章

在同构通量应用程序中,是不是应该在操作中实现 REST api 调用?

如何在 Rails 应用程序中实现 Paypal Rest API

如何在 C# 中实现 YouTrack REST API

Jersey 框架如何在 REST 中实现 JAX-RS API?

如何使用 nodejs 和 express 在 REST API 中实现搜索和过滤

如何在我的 Web 应用程序中实现 REST。我想为我的网站制作一个休息 API?