在Python REST API中实现CSRF保护

Chr*_*nke 6 python security encryption rest csrf

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

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

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

双提交Cookies

为了防止"cookie抛出",Double Submit方法中的令牌需要是可验证的.MiTM攻击是一种额外的威胁,我希望通过仅强制使用HTTPS-cookies来充分缓解这种威胁.

为了获得一个不易被攻击者猜测和复制的可验证令牌,我想像这样的散列令牌应该有效:

pbkdf2_sha256.encrypt($userid + $expire + $mycsrfsecret, salt=$salt)
Run Code Online (Sandbox Code Playgroud)

"exp"是JWT的到期值.JWT将与CSRF-cookie一起发布,服务器可以读取"exp",这会增加一些额外的保护,因为它的变量和攻击者不知道它(可能是多余的?).

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

这种方法会遵循建议的做法吗?

我选择了pbkdf2 over bcrypt,因为它的验证方法明显更快.

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

加密令牌模式

另一种方法是向客户端发送一个字符串,包括userid,expiry和nonce,用服务器端密码加密.在请求时,此字符串将一起发送,服务器可以对其进行解密并验证用户ID和到期日期.

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

  • 我应该在Python中使用什么密码/库?我怎么做Encrypt-then-MAC?
  • 如何将令牌持续到其自然到期之前?我不希望用户每次重新启动浏览器时都必须重新登录.本地存储不是一个安全的地方 - 但没有其他选择.

Vet*_*sin 1

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

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

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

双重提交 Cookie

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

加密令牌模式

这几乎正​​是 JWT 的本质,只需按照建议在标头中传递令牌即可

回答问题:

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