防止CSRF和XSS(哈希+加密)

时间:2018-04-01 11:48:52

标签: rest xss csrf

安全。今天,没有任何应用程序可以在互联网上存活,如果它没有适当的安全程序 - 无论是开发人员使用的框架,还是开发人员自己。我目前正在开发RESTful API以使用Bearer令牌身份验证,但一直在阅读有关XSS和CSRF攻击的内容。

问题1)根据我的阅读,我发现使用基于令牌的身份验证的RESTful API的应用程序容易受到XSS和 CSRF的影响令牌存储在浏览器的localStorage / sessionStorage中,而不是存储在cookie中。这是因为,为了使CSRF起作用,应用程序必须使用cookie。我是对的吗?

但是现在令牌存储在localStorage / sessionStorage中,应用程序很容易受到XSS攻击。如果应用程序的任何部分没有清理输入(例如,Angular输入被框架清理,但是我使用的某个第三方库默认情况下不清理输入),那么攻击者就可以注入恶意代码以窃取其他用户的令牌,然后通过冒充他们来进行经过身份验证的请求。

问题2)有一种方法可以防止使用RESTful API的应用程序中的这两种攻击。我遇到了this post。该文章的要点是,在用户登录并请求持有者令牌时,让服务器还返回一个httpOnly cookie,例如CSRFProtectionCookie。我相信文章中的解决方案非常强大,并提供强大的保护。我再说一遍吗?你有什么看法?

我的申请和上述帖子中提到的方法的版本

上述帖子中提到的方法要求我将CSRFProtectionCookie保存在某种数据库中。我不想那样做。我不希望每次向API发出经过身份验证的请求时都会命中数据库。相反,我能做的就是:

登录

  1. 用户使用用户名和密码
  2. 向用户终端发送POST请求
  3. 授权服务器验证用户凭据并开始使用某些声明构建JWT。
  4. 作为JWT构建的一部分,它还会生成一个随机字符串哈希,然后将其添加为JWT的csrf声明。
  5. 此外,服务器接下来会设置一个名为httpOnly的{​​{1}} Cookie,其值为相同的随机字符串,但此时加密
  6. 将响应返回给浏览器。浏览器将持有者令牌作为响应主体并设置XSRF-TOKEN cookie。
  7. 经过身份验证的请求

    1. 应用程序通过将JWT承载令牌添加为XSRF-TOKEN标头来调用经过身份验证的端点。浏览器会自动发送cookie。

    2. 服务器解密cookie以获取纯文本。然后,服务器使用JWT中存在的哈希验证此纯文本。

    3. 如果匹配,请继续处理请求。否则,返回未经授权的回复。

    4. 我认为这可以防止CSRF和XSS。由于令牌和cookie(httpOnly)都需要进行经过身份验证的请求。

      问题是的,这样就不需要将任何内容持久存储到数据库中了(或者是这样吗?我错过了一些漏洞吗?)。但是,对每个用户请求进行解密和验证哈希的开销是多少?它比数据库I / O更开销吗?此外,欢迎对此方法或其他方法提出任何其他建议!

      谢谢:)

2 个答案:

答案 0 :(得分:2)

如果您使用的是承载身份验证,则任何攻击者都无法使用CSRF,因为他们没有令牌值。浏览器不会自动将其添加到请求中,因此它对CSRF本质上是安全的。有关CSRF的说明以及自定义标头如何缓解它,请参阅here。承载身份验证解决问题的方式与在没有启用CORS的情况下无法添加自定义头的方式相同,或者如果CORS处于活动状态(这对API来说很常见),那么因为使用令牌值本身实现针对API的身份验证,攻击者不会知道要提供的值(如果他们确实只是直接使用没有CSRF的值),浏览器将不会像基本身份验证,摘要等,cookie身份验证或证书一样自动提供身份验证认证。

为了防止XSS(这是一个不同的问题),请确保所有HTML输出都是HTML编码的(>变为>)。这可以在API本身中完成,如果它输出格式化的HTML,或者在JavaScript中,如果由消费者来适当地格式化输出。 JavaScript中包含的函数和JQuery等框架也可以提供帮助(例如textContenttext())。

答案 1 :(得分:1)

回答问题1

  

从我所读过的内容中,我发现使用基于令牌的身份验证的RESTful API的应用程序容易受到XSS的攻击,而不是CSRF,如果令牌存储在浏览器的localStorage / sessionStorage而不是cookie中。这是因为,为了使CSRF起作用,应用程序必须使用cookie。我是对的吗?

或多或少正确。仅使用cookie进行身份验证且没有任何CSRF保护的应用程序将容易受到CSRF攻击,因为cookie会自动包含在所有请求中。

  

但是现在令牌存储在localStorage / sessionStorage中,应用程序很容易受到XSS攻击。

并非应用程序容易受到XSS的攻击,而且身份验证令牌容易受到XSS的攻击。如果您的身份验证令牌以http-only发送,则JavaScript(以及XSS攻击)无法读取该值。

回答问题2

我认为这篇文章很好地解释了如何使用会话cookie和CSRF令牌。让我试着总结一下这篇文章,因为它有点长:

  1. 使用http-only Cookie(理想情况下也是secure - 作者未提及 - 这会阻止浏览器在http请求上发送Cookie,仅阻止https请求)身份验证令牌。通过这种方式,JavaScript无法读取cookie,因此无法在XSS攻击中使用stollen。
  2. 使用会话存储来存储 CSRF保护令牌。这样做的好处是,一些JavaScript代码必须读取此值并将其放入请求中。在某个第三方受感染的站点上运行的恶意代码将无法从本地存储中读取CSRF令牌,因此无法创建有效请求。
  3. 本文还详细介绍了如果您的静态资源与REST端点位于不同的域上,如何设置跨域标头。

    然而,你的方法是倒退到文章所说的内容。您将身份验证令牌放入localStorage并将CSRF令牌放入cookie中。我建议将其翻转回来,因为身份验证令牌比CSRF令牌更重要,而http-only secure cookie对于坏人来说比localStorage更难获得。

    对您的方法的评论

      

    上述帖子中提到的方法要求我将CSRFProtectionCookie保存在某种数据库中。我不想那样做。我不希望每次向API发出经过身份验证的请求时都会命中数据库。

    你正在思考这条路。您所描述的将被称为无状态CSRF令牌"。

    您对#34;经过身份验证的请求的处理方法"看起来不错。我不完全确定你需要加密CSRF令牌值,但它并没有受到伤害。

      

    这消除了将任何内容持久存储到数据库的需要(或者是这样吗?我是否错过了一些漏洞?)

    你是对的,没有漏洞。

      

    但是,对每个用户请求进行解密和验证哈希的开销是多少?它是否比数据库I / O更多开销?

    I / O通常比CPU绑定计算慢得多,即使对于像加密这样的事情也是如此。也就是说,如果你真的担心它,你必须衡量(当然,这说起来容易做起来难。)

    最后的想法......

    请记住,通过将CSRF令牌存储在JWT声明中,只要JWT令牌存在,CSRF令牌就会有效。即使您向客户端发送新的JWT令牌,该旧令牌和CSRF令牌仍然有效。这对于短期令牌(例如10-60分钟)来说不是一个问题,但在服务器端某处存储CSRF令牌的好处之一意味着您可以为超级敏感操作设置一次性令牌。 (另外,如果你需要撤销一个尚未过期的JWT令牌,你也需要在服务器端的某个地方存储这个状态。但是现在我们又陷入了不同的兔子洞...... )

    真正没有特定的框架可以完全阻止XSS漏洞,因为它们可以以多种不同的方式表现出来。也就是说,您的Web应用程序可以使用Content-Security-Policy标头来帮助防止XSS攻击。 CSP标头可用于告诉浏览器允许哪些域加载资源(例如JavaScript文件)。它甚至可以用来防止内联JavaScript运行(这是XSS的主要攻击媒介之一)。