使用 CSP + localStorage 从 CSRF 和 XSS 中保护 Single-page-application
Securing Single-page-application from CSRF and XSS using CSP + localStorage
我有一个单页应用程序,包含敏感内容,需要保护。这个问题是专门针对 XSS 和 CSRF 攻击的。
说明: 很多地方都提示过,比如here to use cookies on top of localStorage while storing the auth-token. A very nice explanation is also provided in answer of another question .
根据这些答案,对于安全内容,建议使用带有“httpOnly”和“secure”选项的cookie来避免XSS;并自己实施 CSRF 保护(类似于 anti-forgery-token in asp.net)(请注意,我不在 Asp .net 上,而是在 java 堆栈上)。
觉得这些博客和谈话有些老了,随着时间的推移,情况有所改变。现在 Contents-Security-Policy header [CSP] with strict policy, risk of XSS attack can be minimized significantly. Also CSP is largely supported in modern-age browsers。考虑到 CSP 的 XSS 安全性,现在我觉得,使用 localStorage 而不是 cookies 来避免 CSRF 是一个不错的选择。
问题:你觉得使用"LocalStorage + CSP (no manual implementation)"有什么disadvantage/security漏洞吗
结束
Cookies [httpOnly 和安全] + CSRF 的“手动”实施 anti-forgery-token?
考虑:
除了 CSP 响应 header,您可以认为 X-XSS-Protection header 仍然根据 的建议得到支持。
您可以考虑该站点是 HTTPS,已实施 HSTS、HPKP 安全 headers。
我最近在考虑一个非常相似的问题 - 但我的场景差异比你的情况影响更大。
具体来说,我在考虑一个 OLTP 应用程序,它对所有 HTML 和 AJAX/SJAX + JSON 使用可缓存内容来检索事务数据。我还没有深入考虑使用传统的 POST 或 AJAX/SJAX 将交易数据发送回服务器。
对我来说,这种方法(相对于传统的 HTML / GET / POST OLTP)的优势在于,除了事务数据之外的所有内容都可以缓存,从而实现最佳容量,并且基于预期的使用场景 性能优势。
它也是在网站上实施 PJAX 的途径,从而消除了从本地缓存检索内容和解析的启动成本。但我在胡扯一些与你的问题无关的东西。
您的 non-cookie 方法类似地将可缓存的内容与数据隔离开来 - 这并非对所有单页应用程序都是严格正确的,但是页面级别转换较少时,净收益不会那么大。
正如您所说,CSP 降低了 XSS 攻击的可能性和影响,但它并没有消除它 - 在脚本存储在受害站点并向访问者重播的情况下。尽管没有真正的 "cross-site",这仍然被描述为一种 XSS 攻击。而且它仍然允许针对 same-origin.
的请求伪造
因此,除非您可以完全确信您的 CSP 永远不会允许 unsafe-inline,否则我认为您仍然需要某种 CSRF 保护。 Microsoft 解决方案很简洁,因为它是无状态的 - 但依赖于单页应用程序的页面 non-cacheable(这消除了性能优势)。
XSS
是您的应用程序中的一个漏洞,允许攻击者让您的常规访问者无端执行第 3 方控制的 javascript。
保护形式必须来自过滤所有用户提供的输入(即使它存储在数据库中),然后通过转义在给定上下文中产生问题的所需字符,在输出上下文中输出它。
身份验证令牌是 XSS 攻击的众多潜在目标之一,将它们存储为 http_only 有助于保护它们,但目前还不足以阻止攻击者。
CSRF
跨站点请求伪造本质上是您的应用程序中的一个漏洞,其中授权用户遵循 link 例如使他们在不知不觉中对您的应用程序执行更改的第 3 方网站。
传统的保护涉及生成一个 "key",您在每个可以进行更改的表单的隐藏字段中输出(并将每个进行更改的按钮转换为具有所述保护的表单)。
密钥必须足够频繁地更改,以便攻击者无法知道它们,猜测它们等,同时它保持足够长的时间相同,用户有时间填写表格。
通常它们可以与会话一起生成,但您不会将它们存储在客户端上,仅以每种形式输出它们并在接受 post 的输入之前检查它们是否存在。
使用本地存储来存储 CSRF 密钥(如果您 确定 所有访问者都支持它)是可能的,但是如果假设所有浏览器都支持它,您会增加问题不正确(它们都会产生 CSRF 违规行为)
HTTP_ONLY
表示浏览器被指示不允许 javascript 访问此 cookie。
这在一定程度上有助于减少 XSS 攻击对该 cookie 的访问(但对攻击者感兴趣的其他内容没有帮助)
安全
表示浏览器被指示仅在使用 https 连接时将此 cookie 发送到服务器(而不是通过 non-https 连接将其发送到同一服务器(它可能会在途中被拦截) ).
放在一起
使用身份验证令牌作为 cookie,使用 https_only 和安全选项。
如果您确定所有客户端都能够进行本地存储,则可以将 CSRF 密钥添加到本地存储并添加 javascript 以将其提取并以每种形式和每个进行更改的按钮将其发送到服务器。如果您将两个键分开,您将两全其美。
但是:您仍然必须检查 CSRF 密钥是否存在并且在每个更改任何内容的请求中都有效。
我个人觉得这还为时过早,在服务器生成的每个表单中使用传统的 CSRF 密钥现在比必须依赖浏览器的假设更容易 and/or 提供回退机制来执行和旧东西一样,必须维护 2 个方法。
CSP
CSP 很好,但目前还不是每个浏览器都支持。如果您依靠它来阻止 XSS,我认为它是一种 "belt and suspenders" 方法,而不是唯一的解决方案。原因很简单:有一天你的负载太大了,决定使用 CDN ...哎呀,现在需要允许 CDN 加载图像、脚本等,现在 XSS 门向该 CDN 的任何其他用户开放。 .. 也许打开那扇门的人甚至没有将 XSS 视为他们需要担心的事情。
此外 context-sensitive 输出过滤并不难写,而且它使得在任何地方输出几乎任何东西都更加安全,并且让过滤器负责编码(例如,你的 URL 会在需要的地方进行 urlencoded ,您的 html 标签的属性会被正确转义,您的文本可以包含 & 和 < 而无需再担心任何事情。
CSP 对我来说是一个相当新的概念,但据我所知,我的答案是:全部使用它们。我会尽量详细说明。
- CSP 相对 易于实施。如果您正在处理敏感内容,那么实施它所增加的成本是值得的。它可以大大提高您的应用程序在支持它的浏览器上的安全性。
- 对于那些能处理它的人来说,这是免费的午餐 - 不理解 header 的浏览器会简单地忽略它。
- 然而,正因为如此,您需要采取所有标准措施。
- CSP 不会(也不能)阻止 CSRF。即使您禁止所有脚本执行,如果不使用 per-request 令牌,CSRF 攻击仍然可能发生。
我有一个单页应用程序,包含敏感内容,需要保护。这个问题是专门针对 XSS 和 CSRF 攻击的。
说明: 很多地方都提示过,比如here to use cookies on top of localStorage while storing the auth-token. A very nice explanation is also provided in answer of another question
根据这些答案,对于安全内容,建议使用带有“httpOnly”和“secure”选项的cookie来避免XSS;并自己实施 CSRF 保护(类似于 anti-forgery-token in asp.net)(请注意,我不在 Asp .net 上,而是在 java 堆栈上)。
觉得这些博客和谈话有些老了,随着时间的推移,情况有所改变。现在 Contents-Security-Policy header [CSP] with strict policy, risk of XSS attack can be minimized significantly. Also CSP is largely supported in modern-age browsers。考虑到 CSP 的 XSS 安全性,现在我觉得,使用 localStorage 而不是 cookies 来避免 CSRF 是一个不错的选择。
问题:你觉得使用"LocalStorage + CSP (no manual implementation)"有什么disadvantage/security漏洞吗
结束
Cookies [httpOnly 和安全] + CSRF 的“手动”实施 anti-forgery-token?
考虑:
除了 CSP 响应 header,您可以认为 X-XSS-Protection header 仍然根据
您可以考虑该站点是 HTTPS,已实施 HSTS、HPKP 安全 headers。
我最近在考虑一个非常相似的问题 - 但我的场景差异比你的情况影响更大。
具体来说,我在考虑一个 OLTP 应用程序,它对所有 HTML 和 AJAX/SJAX + JSON 使用可缓存内容来检索事务数据。我还没有深入考虑使用传统的 POST 或 AJAX/SJAX 将交易数据发送回服务器。
对我来说,这种方法(相对于传统的 HTML / GET / POST OLTP)的优势在于,除了事务数据之外的所有内容都可以缓存,从而实现最佳容量,并且基于预期的使用场景 性能优势。
它也是在网站上实施 PJAX 的途径,从而消除了从本地缓存检索内容和解析的启动成本。但我在胡扯一些与你的问题无关的东西。
您的 non-cookie 方法类似地将可缓存的内容与数据隔离开来 - 这并非对所有单页应用程序都是严格正确的,但是页面级别转换较少时,净收益不会那么大。
正如您所说,CSP 降低了 XSS 攻击的可能性和影响,但它并没有消除它 - 在脚本存储在受害站点并向访问者重播的情况下。尽管没有真正的 "cross-site",这仍然被描述为一种 XSS 攻击。而且它仍然允许针对 same-origin.
的请求伪造因此,除非您可以完全确信您的 CSP 永远不会允许 unsafe-inline,否则我认为您仍然需要某种 CSRF 保护。 Microsoft 解决方案很简洁,因为它是无状态的 - 但依赖于单页应用程序的页面 non-cacheable(这消除了性能优势)。
XSS
是您的应用程序中的一个漏洞,允许攻击者让您的常规访问者无端执行第 3 方控制的 javascript。
保护形式必须来自过滤所有用户提供的输入(即使它存储在数据库中),然后通过转义在给定上下文中产生问题的所需字符,在输出上下文中输出它。
身份验证令牌是 XSS 攻击的众多潜在目标之一,将它们存储为 http_only 有助于保护它们,但目前还不足以阻止攻击者。
CSRF
跨站点请求伪造本质上是您的应用程序中的一个漏洞,其中授权用户遵循 link 例如使他们在不知不觉中对您的应用程序执行更改的第 3 方网站。
传统的保护涉及生成一个 "key",您在每个可以进行更改的表单的隐藏字段中输出(并将每个进行更改的按钮转换为具有所述保护的表单)。 密钥必须足够频繁地更改,以便攻击者无法知道它们,猜测它们等,同时它保持足够长的时间相同,用户有时间填写表格。 通常它们可以与会话一起生成,但您不会将它们存储在客户端上,仅以每种形式输出它们并在接受 post 的输入之前检查它们是否存在。
使用本地存储来存储 CSRF 密钥(如果您 确定 所有访问者都支持它)是可能的,但是如果假设所有浏览器都支持它,您会增加问题不正确(它们都会产生 CSRF 违规行为)
HTTP_ONLY
表示浏览器被指示不允许 javascript 访问此 cookie。 这在一定程度上有助于减少 XSS 攻击对该 cookie 的访问(但对攻击者感兴趣的其他内容没有帮助)
安全
表示浏览器被指示仅在使用 https 连接时将此 cookie 发送到服务器(而不是通过 non-https 连接将其发送到同一服务器(它可能会在途中被拦截) ).
放在一起
使用身份验证令牌作为 cookie,使用 https_only 和安全选项。 如果您确定所有客户端都能够进行本地存储,则可以将 CSRF 密钥添加到本地存储并添加 javascript 以将其提取并以每种形式和每个进行更改的按钮将其发送到服务器。如果您将两个键分开,您将两全其美。 但是:您仍然必须检查 CSRF 密钥是否存在并且在每个更改任何内容的请求中都有效。
我个人觉得这还为时过早,在服务器生成的每个表单中使用传统的 CSRF 密钥现在比必须依赖浏览器的假设更容易 and/or 提供回退机制来执行和旧东西一样,必须维护 2 个方法。
CSP
CSP 很好,但目前还不是每个浏览器都支持。如果您依靠它来阻止 XSS,我认为它是一种 "belt and suspenders" 方法,而不是唯一的解决方案。原因很简单:有一天你的负载太大了,决定使用 CDN ...哎呀,现在需要允许 CDN 加载图像、脚本等,现在 XSS 门向该 CDN 的任何其他用户开放。 .. 也许打开那扇门的人甚至没有将 XSS 视为他们需要担心的事情。
此外 context-sensitive 输出过滤并不难写,而且它使得在任何地方输出几乎任何东西都更加安全,并且让过滤器负责编码(例如,你的 URL 会在需要的地方进行 urlencoded ,您的 html 标签的属性会被正确转义,您的文本可以包含 & 和 < 而无需再担心任何事情。
CSP 对我来说是一个相当新的概念,但据我所知,我的答案是:全部使用它们。我会尽量详细说明。
- CSP 相对 易于实施。如果您正在处理敏感内容,那么实施它所增加的成本是值得的。它可以大大提高您的应用程序在支持它的浏览器上的安全性。
- 对于那些能处理它的人来说,这是免费的午餐 - 不理解 header 的浏览器会简单地忽略它。
- 然而,正因为如此,您需要采取所有标准措施。
- CSP 不会(也不能)阻止 CSRF。即使您禁止所有脚本执行,如果不使用 per-request 令牌,CSRF 攻击仍然可能发生。