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

时间:2016-12-29 21:40:58

标签: javascript security xss csrf

我有一个单页应用程序,具有敏感内容,需要保护。这个问题特别针对XSS和CSRF攻击的防范。

说明:有人建议许多地方(例如here)在存储身份验证令牌时在localStorage上使用Cookie。在回答另一个问题here时,还提供了一个非常好的解释。

根据这些答案,对于安全内容,建议使用带有'httpOnly'和'secure'选项的cookie来避免使用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(无手动实施)”存在任何不利/安全漏洞吗

Cookie [http只有和安全] +“手动”实施CSRF反伪造令牌?

考虑:

除了CSP响应标头之外,您还可以考虑根据here的建议仍支持X-XSS-Protection标头。

您可以认为该网站是HTTPS,已经实施了HSTS,HPKP安全标头。

3 个答案:

答案 0 :(得分:3)

<强> XSS

您的应用程序中存在一个漏洞,允许攻击者让您的常规访问者无理由地执行第三方控制的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标签'属性得到正确转义,您的文字可以包含&amp;和&lt;不必担心任何事情。

答案 1 :(得分:1)

我最近在考虑一个非常类似的问题 - 但我的情景中的差异比你的情况有更大的影响。

具体来说,我正在考虑一个OLTP应用程序,它使用所有HTML的可缓存内容和AJAX / SJAX + JSON来检索事务数据。我还没有深入考虑使用传统的POST或AJAX / SJAX将事务数据发送回服务器。

这种方法对我的优势(通过传统的HTML / GET / POST OLTP)是除了事务数据之外的所有内容都变得可缓存,从而允许最佳容量,并且基于预期的使用场景,性能优势。

它也是在网站上实现PJAX的网关,从而消除了从本地缓存和解析中检索内容的启动成本。但我对与你的问题无关的东西感到好笑。

您的非cookie方法同样将可缓存内容与数据隔离 - 对于所有单页应用程序而言并非严格如此,但是如果页面级别转换较少,则净效益不会太大。

正如您所说,CSP降低了XSS攻击的可能性和影响,但它并没有消除它 - 在脚本存储在受害站点并重放给访问者的情况下。尽管没有真正的“跨站点”,但这仍被描述为一种XSS攻击。它仍然允许请求伪造指向同一起源。

因此,除非您完全确信您的CSP永远不会允许不安全内联,否则我认为您仍然需要某种CSRF保护。 Microsoft解决方案很简洁,因为它是无状态的 - 但依赖于单页面应用程序的页面是不可缓存的(这会消除性能优势)。

答案 2 :(得分:0)

CSP对我来说是一个相当新的概念,但据我所知,我的答案是:全部使用它们。我会试着详细说明。

  1. CSP相对易于实施。如果您正在处理敏感内容,那么实施它的额外成本是值得的。它可以极大地提高支持它的浏览器的应用程序安全性。
  2. 对于那些能够处理它的人来说,这是一个免费的午餐 - 不理解标题的浏览器会忽略它。
  3. 因此,您需要采取所有标准措施。
  4. CSP不会(也不能)阻止CSRF。即使您禁止执行所有脚本,如果没有使用每个请求令牌,仍然可以进行CSRF攻击。