我正在使用 Angular.js(单页应用程序)编写一个胖客户端 Web 应用程序,并且想知道使用 CSRF 令牌保护应用程序的最佳实践是什么。
我应该在首次加载应用程序时发送一个 CSRF 令牌,然后在每个请求中重新使用该令牌吗?我应该有刷新令牌的机制吗?是否有其他保护措施而不是 CSRF 令牌对单页应用程序更有意义?
我正在使用 Angular.js(单页应用程序)编写一个胖客户端 Web 应用程序,并且想知道使用 CSRF 令牌保护应用程序的最佳实践是什么。
我应该在首次加载应用程序时发送一个 CSRF 令牌,然后在每个请求中重新使用该令牌吗?我应该有刷新令牌的机制吗?是否有其他保护措施而不是 CSRF 令牌对单页应用程序更有意义?
这就是我最终实现 CSRF 的方式:
在第一个请求中,将 CSRF 令牌设置为 cookie。每个后续的 AJAX 请求都包含 CSRF 令牌作为X-CSRF-Token
HTTP 标头。
Django 有一些关于如何使用 jQuery 干净利落地执行此操作的文档:https ://docs.djangoproject.com/en/dev/ref/contrib/csrf/
编辑:另一种方法将包含X-Requested-With
标头的请求列入白名单。看来这就是 Rails 所做的。但正如@damio 在下面指出的那样,这X-Requested-With
是一个安全隐患,Django 和 Rails 恢复为不使用它并强制使用令牌。
你很幸运!大约 2 周前,我被问到同样的问题,经过一番摸索,我想出了以下问题。请记住,这没有经过同行评审,所以我们将看看评论和投票的进展情况。就个人而言,我认为这是一个很好的技术。
1. 第一个请求
一旦您收到第一个加载应用程序的请求,生成一个安全的随机标识符并将其存储在服务器上的会话变量中,然后将其发送到客户端。我将它嵌入到之前的页面中</body>
。
<script>setToken('<% print SESSION[TOKEN] %>');</script>
</body>
您setToken()
会将令牌值分配给您保留令牌的变量。
2. 后续请求
对于每个请求,您都会将该令牌添加到参数列表中,例如token=TOKEN
,并且服务将根据存储在会话变量中的那个来检查它。
3. 刷新令牌
这并不是真正的强制性,但每隔一段时间刷新一次令牌是个好主意,比如 15 分钟。当您在令牌过期后收到请求(会话变量中有过期时间)时,您会正常响应(乐观地行动)但在响应中您告诉客户端旧令牌已过期,它应该开始使用新的一个。
客户端通过告诉服务器它现在知道新令牌来对此做出反应,一旦服务器收到该请求,它就会开始使用新令牌并用 OK 消息响应客户端,一旦客户端收到200 OK
它意味着它们都在同步并且客户端开始使用新令牌。
注意:该过程中的一个关键要素是 HTTPS 使用。您不希望中间人嗅探令牌。但是话又说回来,MitM 将能够嗅探 cookie 并劫持会话。