Javascript 如何保护浏览器使用的RESTful API免受CSRF攻击?

Javascript 如何保护浏览器使用的RESTful API免受CSRF攻击?,javascript,security,rest,Javascript,Security,Rest,我正在为一组网站设计API。这些站点非常相似(有点像StackOverflow、SuperUser和ServerFault),它们有一个共享的后端是有意义的。因此,我们决定尝试使用一个好的RESTAPI作为后端,并使用一组非常相似但不同的前端来使用该API。前端最好都是静态的,但如果结果是几乎不可能的话,这不是一个硬性要求 我现在正在设计那个API,我担心安全问题,特别是CSRF。根据我对CSRF攻击的基本理解,它们由两个重要组成部分组成: 能够命名资源和请求主体 诱使用户/浏览器使用环境身份验

我正在为一组网站设计API。这些站点非常相似(有点像StackOverflow、SuperUser和ServerFault),它们有一个共享的后端是有意义的。因此,我们决定尝试使用一个好的RESTAPI作为后端,并使用一组非常相似但不同的前端来使用该API。前端最好都是静态的,但如果结果是几乎不可能的话,这不是一个硬性要求

我现在正在设计那个API,我担心安全问题,特别是CSRF。根据我对CSRF攻击的基本理解,它们由两个重要组成部分组成:

  • 能够命名资源和请求主体

  • 诱使用户/浏览器使用环境身份验证(如会话)向该资源发出看起来经过身份验证的请求

  • 许多修复CSRF攻击的经典方法都基于会话。因为我的RESTAPI并没有真正执行会话,所以这既可以防止很多向量,也可以防止几乎所有修复向量的方法。例如,双重提交没有意义,因为没有什么东西可以双重提交

    我最初的方法是攻击CSRF攻击的第2部分。如果我对所有请求进行身份验证(比如使用HTTP Basic Auth),并且浏览器没有保存这些凭据(例如,一些JS发出了请求),那么只有具有凭据的JS才能发出请求,我们就完成了。明显的缺点是,应用程序需要知道用户的凭据。另一个稍微不那么明显的缺点是,如果我想在API端安全地存储凭据,那么验证密码应该花费固定的、不平凡的时间。如果安全地验证密码需要100毫秒,那么每一个其他请求都需要至少100毫秒+eps,并且需要一些该死的聪明客户端技巧才能让它感觉不慢。我可能能够缓存它(因为凭据总是相同的),如果我非常小心,我可能会设法做到这一点,而不会引入时间漏洞,但这听起来像是黄蜂窝

    OAuth2.0似乎有点过头了,但我想它毕竟可能是最好的解决方案,以免我最终实现得很差。我想我现在可以做HTTP基本身份验证的事情,当我们有第三方应用程序开发人员时,可以转到OAuth

    OAuth有点阻抗不匹配。基本上,OAuth确实希望帮助应用程序访问另一个应用程序上的内容。我希望用户在这样一个帐户存在之前在其中一个前端注册

    我还考虑过通过使URL随机化来攻击第1点——即向查询字符串添加标记。这肯定会起作用,而且它非常接近于表单中传统的随机标记的工作方式,考虑到HATEOAS,它甚至应该是相当安静的,尽管这提出了两个问题:1)从哪里开始?是否存在使用HTTP Basic Auth登录的强制API起点?2) 如果应用程序开发人员不能提前预测URL,他们会高兴多少呢

    我已经看到了,但我不同意随机URI必然无效的前提。而且,这个问题没有任何令人满意的答案,也没有提到OAuth。此外,会话双重提交解决方案无效,正如我前面提到的(静态前端的域与API端点的域不同)


    我意识到,我在这里基本上试图做的是允许来自一个域的跨站点请求,而不允许来自另一个域的跨站点请求,这并不容易。肯定有一些合理的解决方案吗?

    答案取决于您需要支持什么。如果我们假设您希望支持一个使用REST服务的web应用程序,并对一个API使用相同的REST服务,而该API与碰巧是RESTFUL的web应用程序不同(您可能会决定“会话”是为您准备的!)


    目前(/me相当累)我认为您建议的将javascript与HTTP Basic Auth结合使用的方式是一个良好的开端

    根据定义,CSRF令牌是“每用户状态”,因此不是RESTful的。为了安全起见,大多数API都打破了“每个用户状态”的要求,并要求将CSRF令牌作为HTTP头参数传递

    还有其他的方法。检查referer不如CSRF令牌强大,但它是RESTful的,非常不可能被破坏。请记住,缺少推荐人应被视为失败的请求


    XSS可用于绕过基于令牌的CSRF预防和基于referer的CSRF预防

    我有另一个可能的解决方案,所以我将它列为一个答案。请随意拆开:)

    auth.platform.com
    接受身份验证并设置cookie。如果
    auth.site.com
    auth.platform.com
    的CNAME,那么对
    auth.site.com
    的请求(解析后在
    auth.platform.com
    结束)是否能够为
    site.com
    设置cookie?这样我就可以加倍提交会话cookies

    当然,
    auth.platform.com
    只会为一些白名单域设置cookie


    编辑:当然,这一点也不起作用,因为您必须使用HTTPS安全地进行身份验证,HTTPS会识破您的诡计。

    将您的API设计为真正的RESTful API,可以防止最常见的CSRF向量:

    • 避免cookies会防止它们被“偷走”
    • 使用GET进行“安全”操作可以防止
      img
      iframes
      在没有用户交互的情况下触发不安全的操作

    然后,您应该实现让用户的浏览器阻止来自您不信任的来源的请求。

    正如您所说,问题是您既要防止也要允许跨站点请求。问问薛定谔,你知道吗