使用 CSP + localStorage 从 CSRF 和 XSS 保护单页应用程序
Posted
技术标签:
【中文标题】使用 CSP + localStorage 从 CSRF 和 XSS 保护单页应用程序【英文标题】:Securing Single-page-application from CSRF and XSS using CSP + localStorage 【发布时间】:2017-05-14 05:50:30 【问题描述】:我有一个单页应用程序,包含敏感内容,需要保护。这个问题专门针对 XSS 和 CSRF 攻击。
说明:很多地方都建议过,例如here,在存储身份验证令牌时在localStorage 之上使用cookie。在回答另一个问题here时也提供了一个非常好的解释。
基于这些答案,对于安全内容,建议使用带有“httpOnly”和“secure”选项的cookies来避免XSS;并自己实现 CSRF 保护(类似于anti-forgery-token in asp.net)(请注意,我不在 Asp .net 上,而是在 java 堆栈上)。
认为这些博客和对话有些陈旧,并且随着时间的推移,情况发生了一些变化。现在有了Contents-Security-Policy header [CSP] 和严格的策略,XSS 攻击的风险可以显着降低。 CSP 也是largely supported in modern-age browsers。考虑到 CSP 的 XSS 安全性,现在我觉得,使用 localStorage 代替 cookie 来避免 CSRF 是一个不错的选择。
问题:您认为使用“LocalStorage + CSP(无需手动实现)”有什么缺点/安全漏洞
结束
Cookies [httpOnly and secure] + CSRF anti-forgery-token 的“手动”实现?
考虑:
除了 CSP 响应标头之外,您可以考虑按照here 的建议,仍然支持 X-XSS-Protection 标头。
您可以认为该站点是 HTTPS,已实现 HSTS、HPKP 安全标头。
【问题讨论】:
【参考方案1】:XSS
是您的应用程序中的一个漏洞,它允许攻击者让您的常规访问者在未经授权的情况下执行 3rd 方控制的 javascript。
保护表单必须来自过滤所有用户提供的输入(即使它存储在数据库中),然后通过转义在给定上下文中产生问题的所需字符来将其输出到输出上下文中。
身份验证令牌是 XSS 攻击的众多潜在目标之一,将它们存储为 http_only 有助于保护它们,但远远不足以阻止攻击者。
CSRF
跨站点请求伪造本质上是您的应用程序中的一个漏洞,授权用户在该漏洞中点击了一个链接,例如一个第三方网站,使他们在不知不觉中对您的应用程序执行更改。
传统的保护包括生成一个“密钥”,您可以在每个可以进行更改的表单的隐藏字段中输出该“密钥”(并转换每个在具有所述保护的表单中进行更改的按钮)。 密钥必须经常更改,以便攻击者无法知道它们、猜测它们等,同时保持足够长的时间使用户有时间填写表格。 通常它们可以与会话一起生成,但您不要将它们存储在客户端上,仅以每种形式输出它们并在接受帖子输入之前检查它们是否存在。
使用本地存储来存储 CSRF 密钥(如果您确定所有访问者都支持它)是可能的,但如果所有浏览器都支持它的假设不正确(他们'都会产生CSRF违规)
HTTP_ONLY
表示浏览器被指示不允许 javascript 访问此 cookie。 这在一定程度上有助于最大限度地减少 XSS 攻击对该 cookie 的访问(但对攻击者感兴趣的其他事物没有影响)
安全
意味着浏览器被指示仅在使用 https 连接时将此 cookie 发送到服务器(并且不会通过非 https 连接将其发送到同一服务器(它可能会在此过程中被截获)。
组合起来
使用身份验证令牌作为 cookie,带有 https_only 和安全选项。 如果您确定您的所有客户端都能够进行本地存储,您可以将 CSRF 密钥添加到本地存储并添加 javascript 来提取它并以每种形式和每个进行更改的按钮将其发送到服务器。如果您将两把钥匙分开,您将获得两全其美的效果。 但是:您仍然必须检查 CSRF 密钥是否存在并且在每个更改任何内容的请求上都有效。
我个人觉得这还为时过早,而且现在仅在服务器生成的每种形式中使用传统的 CSRF 密钥比必须依赖关于浏览器的假设和/或提供与旧的相同的回退机制更容易事情并且必须维护2个方法。
CSP
CSP 很好,但目前还不是在所有浏览器中都有。如果你依靠它来阻止 XSS,我会认为它是一种“腰带和吊带”的方法,而不是唯一的解决方案。原因很简单:有一天你负载太多,决定使用 CDN ......哎呀,现在需要允许 CDN 加载图像、脚本等,现在 XSS 的大门对那个 CDN 的任何其他用户开放。 .. 也许打开那扇门的那一个甚至没有将 XSS 视为他们需要担心的事情。
此外,上下文相关的输出过滤并不难编写,并且它可以更安全地在任何地方输出任何内容并让过滤器负责编码(例如,您的 URL 将在需要的地方进行 urlencoded,您的 html 标签' 属性得到正确转义,您的文本可以包含 & 和
【讨论】:
【参考方案2】:我最近在考虑一个非常相似的问题 - 但我的情况的差异比你的情况影响更大。
具体来说,我正在考虑一个 OLTP 应用程序,它使用所有 HTML 和 AJAX/SJAX + JSON 的可缓存内容来检索事务数据。我还没有深入考虑使用传统的 POST 或 AJAX/SJAX 将事务数据发送回服务器。
对我来说,这种方法的优势(相对于传统的 HTML / GET / POST OLTP)是除了事务数据之外的所有内容都可以缓存,从而实现最佳容量,并根据预期的使用场景获得性能优势。
它也是在站点上实现PJAX 的门户,从而消除了从本地缓存中检索内容和解析的启动成本。但我在胡扯与你的问题无关的东西。
您的非 cookie 方法类似地将可缓存内容与数据隔离 - 这并非严格适用于所有单页应用程序,但页面级别转换较少,净收益不会那么大。
正如您所说,CSP 降低了 XSS 攻击的可能性和影响,但它并不能消除它 - 在脚本存储在受害网站上并重播给访问者的情况下。尽管没有真正的“跨站点”,但这仍然被描述为一种 XSS 攻击。而且它仍然允许伪造请求指向同源。
因此,除非您完全确信您的 CSP 永远不会允许 unsafe-inline,否则我认为您仍然需要某种 CSRF 保护。 Microsoft 解决方案的简洁之处在于它是无状态的 - 但依赖于您的单页应用程序的页面是不可缓存的(这消除了性能优势)。
【讨论】:
【参考方案3】:CSP 对我来说是一个相当新的概念,但据我所知,我的答案是:全部使用。我会尽量详细说明。
-
CSP相对易于实施。如果您正在处理敏感内容,那么实施它的额外成本是值得的。它可以极大地提高您的应用在支持它的浏览器上的安全性。
对于那些能够处理它的人来说,这是一顿免费的午餐 - 不理解标题的浏览器会简单地忽略它。
因此,您需要准备好所有标准措施。
CSP 不会(也不能)阻止 CSRF。即使您禁止执行所有脚本,如果不使用每个请求令牌,CSRF 攻击仍然可能发生。
【讨论】:
以上是关于使用 CSP + localStorage 从 CSRF 和 XSS 保护单页应用程序的主要内容,如果未能解决你的问题,请参考以下文章
CCF-CSP C/C++ 201909-1 小明种苹果 题解
CCF-CSP C/C++ 201909-2 小明种苹果(续) 题解