跨站脚本攻击预防速查表¶

跨站脚本攻击预防速查表¶
简介¶
本速查表旨在帮助开发人员预防 XSS 漏洞。
跨站脚本攻击(XSS)是一个误称。最初,此术语来源于攻击的早期版本,主要关注跨站窃取数据。此后,该术语的范围扩大到包括基本上任何内容的注入。XSS 攻击是严重的,可能导致账户冒充、观察用户行为、加载外部内容、窃取敏感数据等等。
本速查表包含预防或限制 XSS 影响的技术。由于没有单一的技术可以解决 XSS,因此需要使用正确的防御技术组合来预防 XSS。
框架安全性¶
幸运的是,使用现代 Web 框架构建的应用程序 XSS 漏洞较少,因为这些框架引导开发人员遵循良好的安全实践,并通过使用模板、自动转义等方式帮助缓解 XSS。然而,开发人员需要知道,如果框架使用不安全,例如以下情况,仍然可能出现问题:
框架用于直接操作 DOM 的逃生舱口
React 的dangerouslySetInnerHTML未对 HTML 进行清理
React 无法在没有专门验证的情况下处理javascript:或data: URL
Angular 的bypassSecurityTrustAs*函数
Lit 的unsafeHTML函数
Polymer 的inner-h-t-m-l属性和htmlLiteral函数
模板注入
过时的框架插件或组件
等等
当你使用现代 Web 框架时,你需要了解你的框架如何预防 XSS 以及它存在哪些漏洞。有时你需要在框架提供的保护之外进行操作,这意味着输出编码和 HTML 清理可能至关重要。OWASP 将为 React、Vue 和 Angular 提供针对特定框架的速查表。
XSS 防御理念¶
为了使 XSS 攻击成功,攻击者必须能够在网页中插入并执行恶意内容。因此,Web 应用程序中的所有变量都需要受到保护。确保所有变量都经过验证,然后进行转义或清理,这被称为完美的注入抵抗。任何未经过此过程的变量都是潜在的弱点。框架使确保变量得到正确验证、转义或清理变得容易。
然而,没有哪个框架是完美的,像 React 和 Angular 这样的流行框架中仍然存在安全漏洞。输出编码和 HTML 清理有助于解决这些漏洞。
输出编码¶
当需要安全地显示用户输入的数据时,建议使用输出编码。变量不应被解释为代码而不是文本。本节涵盖了每种形式的输出编码、其使用位置以及何时根本不应使用动态变量。
首先,当您希望按用户输入的方式显示数据时,请从框架的默认输出编码保护开始。自动编码和转义功能内置于大多数框架中。
如果您没有使用框架或需要弥补框架中的不足,那么您应该使用输出编码库。用户界面中使用的每个变量都应通过输出编码函数进行处理。附录中包含了输出编码库的列表。
存在许多不同的输出编码方法,因为浏览器对 HTML、JS、URL 和 CSS 的解析方式不同。使用错误的编码方法可能会引入弱点或损害应用程序的功能。
“HTML 上下文”的输出编码¶
“HTML 上下文”指的是在两个基本 HTML 标签之间插入变量,例如
攻击者可以修改渲染为$varUnsafe的数据。这可能导致攻击被添加到网页中。例如:
为了将变量安全地添加到 Web 模板的 HTML 上下文中,请对该变量使用 HTML 实体编码。
以下是特定字符的编码值示例:
如果您正在使用 JavaScript 写入 HTML,请查看.textContent属性。它是一个安全接收点,并将自动进行 HTML 实体编码。
& &
< <
> >
" "
' '
“HTML 属性上下文”的输出编码¶
当变量被放置在 HTML 属性值中时,就会发生“HTML 属性上下文”。您可能希望这样做来更改超链接、隐藏元素、为图像添加 alt 文本或更改内联 CSS 样式。您应该对放置在大多数 HTML 属性中的变量应用 HTML 属性编码。安全 HTML 属性列表在安全接收点部分提供。
使用引号(如"或')来包围您的变量至关重要。引用使得更改变量操作的上下文变得困难,这有助于防止 XSS。引用还显著减少了您需要编码的字符集,使您的应用程序更可靠,编码更容易实现。
如果您正在使用 JavaScript 写入 HTML 属性,请查看.setAttribute和[attribute]方法,因为它们将自动进行 HTML 属性编码。只要属性名称是硬编码且无害的(如id或class),它们就是安全接收点。通常,接受 JavaScript 的属性,例如onClick,与不受信任的属性值一起使用时是不安全的。
“JavaScript 上下文”的输出编码¶
“JavaScript 上下文”指的是变量被放入内联 JavaScript 并嵌入 HTML 文档中的情况。这种情况在大量使用嵌入网页中的自定义 JavaScript 的程序中很常见。
然而,在 JavaScript 中放置变量的唯一“安全”位置是在“带引号的数据值”内。所有其他上下文都是不安全的,您不应在其中放置变量数据。
“带引号数据值”的示例:
使用\xHH格式编码所有字符。编码库通常有EncodeForJavaScript或类似的功能来支持此功能。
请查看OWASP Java 编码器 JavaScript 编码示例,了解需要最少编码的正确 JavaScript 使用示例。
对于 JSON,请验证Content-Type头部是application/json而不是text/html,以防止 XSS。
“CSS 上下文”的输出编码¶
“CSS 上下文”指的是变量被放入内联 CSS 中,这在开发人员希望用户自定义网页外观时很常见。由于 CSS 具有惊人的强大功能,它已被用于多种类型的攻击。变量只应放置在 CSS 属性值中。其他“CSS 上下文”是不安全的,您不应在其中放置变量数据。
Oh no
如果您正在使用 JavaScript 更改 CSS 属性,请考虑使用style.property = x。这是一个安全接收点,并将自动对其中的数据进行 CSS 编码。
在将变量插入 CSS 属性时,请确保数据经过正确编码和清理,以防止注入攻击。避免将变量直接放入选择器或其他 CSS 上下文。
“URL 上下文”的输出编码¶
“URL 上下文”指的是变量被放入 URL 中。最常见的是,开发人员会将参数或 URL 片段添加到 URL 基础中,然后将其显示或用于某些操作。对于这些场景,请使用 URL 编码。
使用%HH编码格式编码所有字符。确保所有属性都完全加引号,与 JS 和 CSS 相同。
常见错误¶
在某些情况下,你会在不同的上下文中使用 URL。最常见的情况是将其添加到标签的href或src属性中。在这种情况下,你应该先进行 URL 编码,然后进行 HTML 属性编码。
url = "https://site.com?data=" + urlencode(parameter)
如果您正在使用 JavaScript 构造 URL 查询值,请考虑使用window.encodeURIComponent(x)。这是一个安全接收点,并将自动对其中的数据进行 URL 编码。
危险上下文¶
输出编码并非完美无缺。它并不总是能阻止 XSS。这些位置被称为危险上下文。危险上下文包括:
其他需要注意的区域包括:
回调函数
代码中处理 URL 的位置,例如此 CSS { background-url : “javascript:alert(xss)”; }
所有 JavaScript 事件处理程序(onclick(), onerror(), onmouseover())。
不安全的 JS 函数,如eval(), setInterval(), setTimeout()
不要将变量放入危险上下文,即使进行输出编码,也无法完全阻止 XSS 攻击。
HTML 清理¶
当用户需要编写 HTML 时,开发人员可能会允许用户在所见即所得编辑器中更改内容的样式或结构。在这种情况下,输出编码将阻止 XSS,但会破坏应用程序的预期功能。样式将无法渲染。在这种情况下,应使用 HTML 清理。
HTML 清理将从变量中去除危险的 HTML,并返回一个安全的 HTML 字符串。OWASP 推荐使用DOMPurify进行 HTML 清理。
let clean = DOMPurify.sanitize(dirty);
还有一些其他事项需要考虑:
如果您清理内容后又对其进行修改,您很容易就会使您的安全工作失效。
如果您清理内容后将其发送给某个库使用,请检查它是否以某种方式更改了该字符串。否则,同样地,您的安全努力也会失效。
您必须定期修补您使用的 DOMPurify 或其他 HTML 清理库。浏览器功能会不断变化,并且绕过方式也经常被发现。
安全接收点¶
安全专业人员通常使用源和接收点来讨论。如果你污染了一条河流,它会流向下游的某个地方。计算机安全也是如此。XSS 接收点是变量被放置到你的网页中的位置。
值得庆幸的是,许多可以放置变量的接收点是安全的。这是因为这些接收点将变量视为文本,并且永远不会执行它。尝试重构你的代码,移除对不安全接收点的引用,如 innerHTML,而是使用 textContent 或 value。
elem.textContent = dangerVariable;
elem.insertAdjacentText(dangerVariable);
elem.className = dangerVariable;
elem.setAttribute(safeName, dangerVariable);
formfield.value = dangerVariable;
document.createTextNode(dangerVariable);
document.createElement(dangerVariable);
elem.innerHTML = DOMPurify.sanitize(dangerVar);
安全的 HTML 属性包括:align, alink, alt, bgcolor, border, cellpadding, cellspacing, class, color, cols, colspan, coords, dir, face, height, hspace, ismap, lang, marginheight, marginwidth, multiple, nohref, noresize, noshade, nowrap, ref, rel, rev, rows, rowspan, scrolling, shape, span, summary, tabindex, title, usemap, valign, value, vlink, vspace, width。
对于未在此处列出的属性,请确保如果提供了 JavaScript 代码作为值,则不能执行它。
其他控制措施¶
框架安全保护、输出编码和 HTML 清理将为您的应用程序提供最佳保护。OWASP 在所有情况下都推荐这些措施。
除了上述措施外,请考虑采用以下控制措施。
Cookie 属性 - 这些属性改变了 JavaScript 和浏览器与 Cookie 的交互方式。Cookie 属性试图限制 XSS 攻击的影响,但不能阻止恶意内容的执行或解决漏洞的根本原因。
内容安全策略(CSP)- 一个阻止内容加载的允许列表。实现时很容易出错,因此不应将其作为主要的防御机制。将 CSP 作为额外的防御层,并查看此处的速查表。
Web 应用防火墙(WAFs)- 它们查找已知的攻击字符串并阻止它们。WAF 不可靠,新的绕过技术不断被发现。WAF 也无法解决 XSS 漏洞的根本原因。此外,WAF 还遗漏了一类完全在客户端运行的 XSS 漏洞。不建议使用 WAF 来阻止 XSS,尤其是基于 DOM 的 XSS。
XSS 预防规则摘要¶
这些 HTML 片段展示了如何在各种不同上下文中安全地渲染不可信数据。
数据类型:字符串 上下文:HTML 正文 代码:不可信数据 示例防御:HTML 实体编码(规则 #1)
数据类型:字符串 上下文:安全 HTML 属性 代码: 示例防御:激进的 HTML 实体编码(规则 #2),仅将不可信数据放入安全属性列表(如下所列),严格验证不安全属性如 background, ID 和 name。
数据类型:字符串 上下文:GET 参数 代码:点击我 示例防御:URL 编码(规则 #5)。
数据类型:字符串 上下文:SRC 或 HREF 属性中的不可信 URL 代码:点击我 示例防御:规范化输入,URL 验证,安全 URL 验证,只允许 http 和 HTTPS URL(避免使用 JavaScript 协议打开新窗口),属性编码器。
数据类型:字符串 上下文:CSS 值 代码:HTML
数据类型:字符串 上下文:JavaScript 变量 代码: 示例防御:确保 JavaScript 变量被引用,JavaScript 十六进制编码,JavaScript Unicode 编码,避免反斜杠编码(\" 或 \' 或 \\)。
数据类型:HTML 上下文:HTML 正文 代码:
数据类型:字符串 上下文:DOM XSS 代码: