我正在为一组网站设计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)你从哪里开始?是否存在使用HTTP Basic Auth登录的强制API起点? 2)如果他们无法预先预测URL,那么它会让应用程序开发人员满意多少,HATEOAS会被诅咒?
我见过How to prevent CSRF in a RESTful application?,但我不同意随机URI必然是不可靠的前提。此外,这个问题并没有真正令人满意的答案,也没有提到OAuth。此外,会话双提交解决方案无效,如上所述(静态前端的域不是API端点)。
我意识到我从根本上试图在这里做的是尝试允许来自一个域的跨站点请求而不允许它们从另一个域中进行,这并不容易。当然必须有一些合理的解决方案吗?
答案 0 :(得分:3)
根据定义,CSRF令牌是“按用户状态”,因此不是RESTful。出于安全考虑,大多数API都会破坏其“每用户状态”要求,并要求将CSRF令牌作为HTTP标头参数传递。
preventing CSRF还有其他方法。检查referer不如CSRF令牌那么强,但它是RESTful的,并且非常不太可能被破坏。请记住,缺少引用者应被视为失败的请求。
XSS可用于绕过基于令牌的CSRF预防和基于引用的CSRF预防。
答案 1 :(得分:0)
答案取决于您需要支持的内容。如果我们假设您希望支持使用 REST服务的Web应用程序,并使用相同的REST服务来获取与Web应用程序不同的API(恰好是RESTFUL)(您可以决定'会话'是给你的!)。
现在(/我相当累)我认为你建议在HTTP Basic Auth中使用javascript的方式是一个好的开始。
答案 2 :(得分:0)
我有另一种可能的解决方案,所以我将其列为答案。请随意将它拆开:)
auth.platform.com
接受身份验证并设置Cookie。如果auth.site.com
是auth.platform.com
的CNAME,那么auth.site.com
的请求(解决后最后为auth.platform.com
)是否可以为site.com
设置Cookie?这样我就可以双重提交会话cookie。
当然,auth.platform.com
只会为少数列入白名单的域设置Cookie。
编辑:当然,这根本不起作用,因为你必须使用HTTPS安全地进行身份验证,而HTTPS将会看到你的诡计。
答案 3 :(得分:0)
将您的API设计为真正的RESTful,可以阻止最常见的CSRF向量:
img
和iframes
在没有用户交互的情况下触发不安全的操作。然后你应该实施CORS让用户'浏览器阻止来自您不信任的来源的请求。