【问题标题】:Protection against CSRF and XSS (Hashing + Encrypting)防止 CSRF 和 XSS(哈希 + 加密)
【发布时间】:2018-09-10 20:51:28
【问题描述】:

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

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

但是现在令牌存储在 localStorage/sessionStorage 中,应用程序变得容易受到 XSS 攻击。如果应用程序的任何部分没有清理输入(例如,Angular 输入由框架清理,但我使用的某个第 3 方库可能默认不清理输入),那么攻击者可以注入恶意代码窃取其他用户的令牌,然后通过模拟他们发出经过身份验证的请求。

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

我的应用程序和我上面帖子中提到的方法的版本

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

登录

  1. 用户使用用户名和密码向令牌端点发送 POST 请求
  2. 授权服务器验证用户凭据并开始使用某些声明构建 JWT。
  3. 作为 JWT 构建的一部分,它还会生成一个随机字符串,对其进行散列,然后将其作为 csrf 声明添加到 JWT。
  4. 此外,接下来服务器设置一个名为XSRF-TOKENhttpOnly cookie,其值是相同的随机字符串,但这次加密
  5. 将响应返回给浏览器。浏览器获取不记名令牌作为响应正文,并设置了 XSRF-TOKEN cookie。

经过身份验证的请求

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

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

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

我认为这可以同时防止 CSRF 和 XSS。因为需要令牌和 cookie (httpOnly) 才能发出经过身份验证的请求。

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

谢谢:)

【问题讨论】:

  • 你不必坚持任何东西来有效地防止 csrf,请参阅双重发布。 XSS 不会被任何框架完全缓解,而且你似乎并不了解 XSS,所以要小心那个。您的方法不提供保护。施奈尔定律也适用。 :)
  • 施奈尔定律让人觉得自己像个傻瓜 xD 但是是的,我会马上阅读关于双重发布的内容!另外,您能否解释一下这个版本如何/为什么不提供保护?

标签: rest xss csrf


【解决方案1】:

问题 1 的答案

根据我的阅读,如果令牌存储在浏览器的 localStorage/sessionStorage 而不是 cookie 中,则使用基于令牌的身份验证的 RESTful API 的应用程序容易受到 XSS 而不是 CSRF 的攻击。这是因为,要使 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请求)作为身份验证 令牌。这样,cookie 就无法被 JavaScript 读取,因此无法在 XSS 攻击中被窃取。
  2. 使用会话存储来存储 CSRF 保护 令牌。这里的好处是一些 JavaScript 代码必须读取该值并将其放入请求中。在某个第 3 方运行的恶意代码,受感染的站点将无法从本地存储读取 CSRF 令牌,因此无法创建有效请求。

本文还详细介绍了如果您的静态资源位于与 REST 端点不同的域中,如何设置跨域标头。

但是,您的方法与文章所说的相反。您将身份验证令牌放入 localStorage 并将 CSRF 令牌放入 cookie。我建议将其翻转过来,因为身份验证令牌比 CSRF 令牌更重要,而且对于坏人来说,http-only secure cookie 比 localStorage 更难获得。

对您的方法的评论

上面帖子中提到的方法要求我将CSRFProtectionCookie 持久化到某种数据库中。我不想那样做。我不希望每次向 API 发出经过身份验证的请求时都会访问数据库。

在这里,您正在沿着一条好的道路思考。您所描述的将被称为“无状态 CSRF 令牌”。

您对“经过身份验证的请求”的处理方法看起来不错。我不完全确定您是否需要加密 CSRF 令牌值,但这并没有什么坏处。

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

你是对的,没有漏洞。

但是在每个用户请求上解密和验证哈希的开销是多少?是否比数据库 I/O 开销更大?

I/O 通常比 CPU 密集型计算慢得多,即使对于加密之类的计算也是如此。也就是说,如果您真的担心,就必须进行测量(当然,说起来容易做起来难)。

最后的想法...

请记住,通过将 CSRF 令牌存储在 JWT 声明中,CSRF 令牌将与 JWT 令牌一样有效。即使您向客户端发送新的 JWT 令牌,旧令牌和 CSRF 令牌仍然有效。对于短期令牌(比如 10-60 分钟)来说,这不是问题,但是将 CSRF 令牌存储在服务器端某处的好处之一意味着您可以拥有一次性令牌用于超敏感操作。 (此外,如果您需要撤销尚未过期的 JWT 令牌,您也需要将该状态存储在服务器端的某个位置。但现在我们掉进了另一个兔子洞……)

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

【讨论】:

  • 阅读这个答案让我很开心。您仔细剖析了问题并回答了相关问题。非常感谢!至于翻转身份验证令牌和cookie - 我没有这样做是有原因的。如果我需要在本机应用程序(例如 android)中使用此应用程序,那么我只能考虑请求的身份验证令牌(并且我计划使用每个请求的 User-Agent 标头来区分客户端。基于浏览器的应用程序无法修改 User-Agent 标头,但本机应用程序可以将其设置为“User-Agent:NativeApp”之类的内容 - 在这种情况下,忽略缺少 cookie。
【解决方案2】:

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

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

【讨论】:

  • 谢谢!关于 CSRF 的第一段完全有道理。但我更担心的是 XSS,因为如果开发人员在任何时候都没有意识到 HTML 编码——可能是人为错误的结果,这种漏洞似乎很容易潜入你的代码。
  • @AninditKarmakar 不幸的是,这只是野兽的本性。 XSS 漏洞很容易创建。
猜你喜欢
  • 2018-09-19
  • 2020-06-15
  • 2014-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 2016-03-20
  • 1970-01-01
相关资源
最近更新 更多