使用 CSP + localStorage 从 CSRF 和 XSS 保护单页应用程序

Vis*_*hal 5 javascript security xss csrf

我有一个单页应用程序,包含敏感内容,需要保护。这个问题是专门针对 XSS 和 CSRF 攻击的。

说明:很多地方都提出了建议,例如这里在存储 auth-token 的同时在 localStorage 之上使用 cookie。此处还提供了一个很好的解释来回答另一个问题。

基于这些答案,对于安全内容,建议使用带有“httpOnly”和“secure”选项的 cookie 以避免 XSS;并由我们自己实现 CSRF 保护(类似于asp.net 中的防伪令牌)(请注意,我不是在 Asp .net 上,而是在 java 堆栈上)。

以为这些博客和对话有些陈旧,随着时间的流逝,场景有所改变。现在使用具有严格策略的Contents-Security-Policy 标头 [CSP],可以显着降低 XSS 攻击的风险。此外,现代浏览器在很大程度上支持CSP 。考虑到 CSP 的 XSS 安全性,现在我觉得使用 localStorage 而不是 cookie 来避免 CSRF 是一个不错的选择。

问题:您认为使用“LocalStorage + CSP(无需手动实现)”有什么缺点/安全漏洞吗?

超过

Cookies [httpOnly and secure] + CSRF 防伪令牌的“手动”实现?

考虑:

除了 CSP 响应标头之外,您还可以考虑按照此处的建议仍然支持 X-XSS-Protection 标头。

您可以考虑该站点是 HTTPS,具有 HSTS、HPKP 安全标头的实现。

小智 6

跨站脚本攻击

是您的应用程序中的一个漏洞,允许攻击者让您的常规访问者未经授权地执行第 3 方控制的 JavaScript。

保护形式必须来自过滤所有用户提供的输入(即使它存储在数据库中),然后通过转义在给定上下文中产生问题的所需字符将其输出到输出上下文中。

身份验证令牌是 XSS 攻击的众多潜在目标之一,将它们存储为 http_only 有助于保护它们,但到目前为止还不足以阻止攻击者。

CSRF

跨站点请求伪造本质上是您的应用程序中的一个漏洞,其中授权用户点击第三方网站上的链接,使他们在不知不觉中对您的应用程序执行更改。

传统的保护涉及生成一个“密钥”,您可以在每个可以进行更改的表单的隐藏字段中输出该“密钥”(并转换具有所述保护的表单中进行更改的每个按钮)。密钥必须经常更改,以便攻击者无法知道它们、猜测它们等,同时密钥保持足够长的时间,以便用户有时间填写表单。通常,它们可以与会话一起生成,但您不会将它们存储在客户端上,仅以每种形式输出它们,并在接受帖子的输入之前检查它们是否存在。

使用本地存储来存储 CSRF 密钥(如果您确定所有访问者都支持它)是一种可能,但如果所有浏览器都支持它的假设不正确(它们都会生成 CSRF 违规),则会增加问题

HTTP_ONLY

意味着浏览器被指示不要让 javascript 访问此 cookie。这在一定程度上有助于最大限度地减少 XSS 攻击对此 cookie 的访问(但不会影响攻击者感兴趣的其他内容)

安全的

意味着浏览器被指示仅在使用 https 连接时将此 cookie 发送到服务器(并且不会通过非 https 连接将其发送到同一服务器(可能会在途中被拦截)。

把它放在一起

使用身份验证令牌作为 cookie,并带有 https_only 和 secure 选项。如果您确定所有客户端都能够进行本地存储,则可以将 CSRF 密钥添加到本地存储,并添加提取该密钥的 javascript,并将其以每个表单和每个进行更改的按钮发送到服务器。如果您将两把钥匙分开,您将获得两全其美的效果。但是:您仍然需要检查 CSRF 密钥在每个更改任何内容的请求中是否存在且有效。

就我个人而言,我觉得这还为时过早,而且现在在服务器生成的每种表单中使用传统的 CSRF 密钥比必须依赖于浏览器的假设和/或提供与旧的东西相同的后备机制更容易维持2个方法。

太阳能光伏发电

CSP 很好,但到目前为止还不是在每个浏览器中都适用。如果您依靠它来阻止 XSS,我会将其视为“腰带和吊带”方法,而不是唯一的解决方案。原因很简单:有一天,您负载过多,决定使用 CDN ...哎呀,现在需要允许 CDN 加载图像、脚本等,而现在 XSS 之门对该 CDN 的任何其他用户开放。 .. 也许打开那扇门的人甚至没有考虑到 XSS 是他们需要担心的事情。

此外,上下文相关的输出过滤并不难编写,并且它使得在任何地方输出任何内容都变得更加安全,并且让过滤器负责编码(例如,您的 URL 将在需要的地方进行 urlencoded,您的 html 标签的属性将得到正确转义,您的文本可以包含 & 和 < ,而不必再担心任何事情。