【发布时间】:2012-01-02 20:09:34
【问题描述】:
我正在为一组网站设计 API。这些站点非常相似(有点像 StackOverflow、SuperUser 和 ServerFault),它们有一个共享的后端是有意义的。因此,我们决定尝试使用一个不错的 REST API 作为后端,并使用一堆非常相似但不同的前端来使用该 API。前端最好都是静态的,但如果结果证明是不可能的,这不是硬性要求。
我现在正在设计该 API,我担心安全隐患,尤其是 CSRF。根据我对 CSRF 攻击的基本理解,它们由两个重要组成部分组成:
能够命名资源和请求正文。
诱使用户/浏览器使用环境身份验证(如会话)向看起来经过身份验证的资源发出请求。
许多修复 CSRF 攻击的经典方法都是基于会话的。由于我的 REST API 并没有真正进行会话,这既阻止了很多向量,也阻止了几乎所有修复它们的方法。例如,双重提交没有意义,因为没有什么可以双重提交。
我最初的方法涉及攻击 CSRF 攻击的第 2 部分。如果我对所有请求进行身份验证(例如使用 HTTP Basic Auth),并且浏览器不保存这些凭据(例如,某些 JS 发出请求),那么只有具有凭据的 JS 才能发出请求,我们就完成了.明显的缺点是应用程序需要知道用户的凭据。另一个不太明显的缺点是,如果我想在 API 端安全地存储凭据,那么验证密码应该花费固定的、重要的时间。如果安全地验证密码需要 100 毫秒,那么每个其他请求将至少需要 100 毫秒 + eps,并且需要一些非常聪明的客户端技巧才能让这感觉不慢。我也许可以缓存它(因为凭据将始终相同),如果我非常小心,我可能会设法做到这一点而不会引入计时漏洞,但这听起来像马蜂窝。
OAuth 2.0 似乎有点过头了,但我想它毕竟可能是最好的解决方案,以免我最终实施得很糟糕。我想我现在可以做 HTTP Basic Auth 的事情,当我们有第三方应用程序开发人员时,我可以转向 OAuth。
与 OAuth 存在一些阻抗不匹配。基本上,OAuth 真的想帮助应用程序访问另一个应用程序上的东西。我希望用户在这样的帐户存在之前注册其中一个前端。
我还考虑了通过使 URL 随机化来攻击第 1 点——即将标记添加到查询字符串。这肯定会奏效,并且非常接近表单中传统随机令牌的工作方式,并且考虑到 HATEOAS,它甚至应该是相当 RESTful 的,尽管这引发了两个问题:1)你从哪里开始?是否有一个强制性的 API 起点,您可以使用 HTTP Basic Auth 登录? 2) 如果应用开发者不能预先预测一个 URL,那该死的 HATEOAS 会让他们高兴吗?
我见过How to prevent CSRF in a RESTful application?,但我不同意随机 URI 必然是非 RESTful 的前提。此外,这个问题并没有真正令人满意的答案,也没有提到 OAuth。此外,正如我上面提到的(静态前端的域与 API 端点的域不同),会话双重提交解决方案无效。
我意识到我在这里所做的基本上是尝试允许来自一个域的跨站点请求并禁止来自另一个域的跨站点请求,这并不容易。肯定有一些合理的解决方案?
【问题讨论】:
-
如您所说,问题在于您既要阻止跨站点请求又要允许跨站点请求。问薛定谔。
-
这并不意味着没有办法解决问题。我什至提供了一个,虽然有点慢。
标签: javascript security rest