目录
1、概述
2、XSS普遍认可三种形式:
2.1 反射式 XSS 攻击
2.2 存储的 XSS 攻击
2.3 基于DOM的XSS 攻击
2.3.1 DOM中相关建议:
2.3.2 利用javascript开发时的建议规则:
3、XSS 攻击后果
4、框架安全
5、XSS 防御理念
6、XSS Payload
7、源码扫描
1、概述
跨站点脚本 (XSS) 攻击是一种注入,其中 恶意脚本被注入到其他良性和受信任的脚本中 网站。当攻击者使用 Web 应用程序执行以下操作时,会发生 XSS 攻击 发送恶意代码(通常以浏览器端脚本的形式)到 不同的最终用户。允许这些攻击成功的缺陷是 相当普遍,并且发生在 Web 应用程序使用来自 用户在其生成的输出中,而无需对其进行验证或编码。
攻击者可以使用 XSS 向毫无戒心的人发送恶意脚本 用户。最终用户的浏览器无法知道脚本应该 不可信,并将执行脚本。因为它认为 脚本来自受信任的来源,恶意脚本可以访问任何 Cookie、会话令牌或 浏览器并与该站点一起使用。这些脚本甚至可以重写 网页的内容。
2、XSS普遍认可三种形式:
- 反射
- 存储
- 基本DOM的XSS
为了理解基于 DOM 的 XSS,与基于 DOM 的 XSS 相比,需要了解反射式和存储型 XSS 之间的根本区别。主要区别在于攻击注入应用程序的位置。
反射和存储的XSS是服务器端注入问题,而基于DOM的XSS是客户端(浏览器)端注入问题。
所有这些代码都源自服务器,这意味着应用程序所有者有责任使其免受 XSS 的攻击,无论它是什么类型的 XSS 缺陷。此外,XSS 攻击始终在浏览器中执行。
反射/存储XSS之间的区别在于攻击被添加或注入到应用程序中。使用反射/存储,攻击在服务器端处理请求期间注入到应用程序中,其中不受信任的输入被动态添加到 HTML 中。对于 DOM XSS,攻击在运行时直接注入客户端中的应用程序中。
当浏览器呈现 HTML 和任何其他关联内容(如 CSS 或 JavaScript)时,它会为不同类型的输入识别各种呈现上下文,并为每个上下文遵循不同的规则。呈现上下文与 HTML 标记及其属性的分析相关联。
- 呈现上下文的 HTML 解析器指示数据在页面上的呈现和布局方式,并且可以进一步细分为 HTML、HTML 属性、URL 和 CSS 的标准上下文。
- 执行上下文的 JavaScript 或 VBScript 解析器与脚本代码的解析和执行相关联。每个解析器都有不同且独立的语义,因为它们可以执行脚本代码,这使得创建一致的规则来缓解各种上下文中的漏洞变得困难。执行上下文中每个子上下文(HTML、HTML 属性、URL 和 CSS)中编码值的不同含义和处理方式使复杂性更加复杂。
出于本文的目的,我们将 HTML、HTML 属性、URL 和 CSS 上下文称为子上下文,因为可以在 JavaScript 执行上下文中访问和设置这些上下文中的每一个。
在 JavaScript 代码中,主要上下文是 JavaScript,但使用正确的标记和上下文结束字符,攻击者可以尝试使用等效的 JavaScript DOM 方法攻击其他 4 个上下文。
以下是在 JavaScript 上下文和 HTML 子上下文中发生的一个示例漏洞:
2.1 反射式 XSS 攻击
反射式攻击是指注入的脚本被反射掉的攻击 Web 服务器,例如在错误消息、搜索结果或任何其他 包含发送到服务器的部分或全部输入的响应 请求的一部分。反射攻击通过以下方式传递给受害者 其他路由,例如在电子邮件中或在某些其他网站上。 当用户被诱骗点击恶意链接时,提交 特制表单,甚至只是浏览到恶意网站, 注入的代码会传输到易受攻击的网站,这反映了 攻击回用户的浏览器。然后浏览器执行代码 因为它来自“受信任”的服务器。反射的XSS有时也是 称为非持久性或类型 I XSS(攻击被执行 通过单个请求/响应周期)。
2.2 存储的 XSS 攻击
存储攻击是那些永久存储注入脚本的攻击 在目标服务器上,例如在数据库中,在消息论坛中, 访客日志、评论字段等然后受害者检索恶意 服务器请求存储信息时的脚本。数据处理 XSS 有时也称为持久或 II 类 XSS。
2.3 基于DOM的XSS 攻击
2.3.1 DOM中相关建议:
规则一:
要在 DOM 中对 HTML 进行动态更新,我们建议:
- HTML 编码,然后
- JavaScript 对所有不受信任的输入进行编码,如以下示例所示:
规则二:
HTML 属性插入不受信任的数据。
当你在 DOM 执行上下文中时,你只需要对不执行代码的 HTML 属性(事件处理程序、CSS 和 URL 属性以外的属性)进行 JavaScript 编码。
例如,一般规则是将 HTML 属性编码放置在 HTML 属性中的不受信任的数据(来自数据库、HTTP 请求、用户、后端系统等的数据)。这是在呈现上下文中输出数据时要采取的适当步骤,但是在执行上下文中使用 HTML 属性编码将中断应用程序显示数据。
示例如下:
正确示例如下:
规则三:
将不受信任的数据插入事件中。
将动态数据放在 JavaScript 代码中尤其危险,因为与其他编码相比,JavaScript 编码对 JavaScript 编码数据具有不同的语义。在许多情况下,JavaScript 编码不会阻止执行上下文中的攻击。例如,JavaScript 编码的字符串即使它是 JavaScript 编码的,也会执行。
因此,主要建议是避免在此上下文中包含不受信任的数据。如果必须,以下示例描述了一些有效和无效的方法。
规则四:
将不受信任的数据插入CSS属性中
通常,从CSS上下文执行JavaScript需要传递给CSS方法或调用CSS方法传递JavaScript代码直接执行。javascript:attackCode()
url()
expression()
根据我的经验,从执行上下文 (JavaScript) 调用函数已被禁用。为了缓解 CSS 方法,请确保对传递给 CSS 方法的数据进行 URL 编码。expression()
url()
url()
规则五:
将不受信任的数据插入到URL中。
在执行和呈现上下文中解析 URL 的逻辑看起来是相同的。因此,执行 (DOM) 上下文中 URL 属性的编码规则几乎没有变化。
规则六:
使用安全的javascript 函数或属性填充DOM
用不受信任的数据填充 DOM 的最基本安全方法是使用 安全赋值属性 。textContent
下面是安全使用的示例。
规则七:
修复DOM跨站点脚本漏洞
修复基于 DOM 的跨站点脚本的最佳方法是使用正确的输出方法(接收器)。例如,如果要使用用户输入来写入元素,请不要使用 ,而是使用 或 。这将解决问题,并且是修复基于 DOM 的 XSS 漏洞的正确方法。div tag
innerHtml
innerText
textContent
在危险源(如 eval)中使用用户控制的输入始终是一个坏主意。99%的情况下,这表明编程实践不好或懒惰,所以不要这样做,而不是试图清理输入。
最后,为了解决我们初始代码中的问题,而不是尝试正确编码输出,这很麻烦并且很容易出错,我们只需将其编写在这样的内容中:element.textContent
2.3.2 利用javascript开发时的建议规则:
基于 DOM 的 XSS 极难缓解,因为它的攻击面很大,而且浏览器之间缺乏标准化。
下面的指南试图为开发人员在开发基于 Web 的 JavaScript 应用程序 (Web 2.0) 时提供指南,以便他们可以避免使用 XSS。
规则一:
避免不受信任的数据视为代码或者javascript 代码中的标记。
规则二:
在构建模板化的javascript时,应对不信任数据进行编码。
规则三:
使用 document.createElement(“...”)、element.setAttribute(“...”,“value”)、element.appendChild(...) 和类似的东西来构建动态接口
请注意,仅对有限数量的属性是安全的。element.setAttribute
危险属性包括作为命令执行上下文的任何属性,例如 或 。onclickonblur
安全属性的示例包括:
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
规则四:
避免将不信任的数据,放到HTML中。
避免使用不受信任的数据填充以下方法。
element.innerHTML = "...";
element.outerHTML = "...";
document.write(...);
document.writeln(...);
规则五:
避免将eval() 数据隐式传递
确保传递给这些方法的任何不受信任的数据是:
- 用字符串分隔符分隔
- 包含在闭包或根据使用情况编码为 N 级的 JavaScript 中
- 包装在自定义函数中。
确保按照上面的步骤 3 操作,以确保不受信任的数据不会发送到自定义函数中的危险方法,或者通过添加额外的编码层来处理它。
规则六:仅在表达式右侧使用不受信任的数据
仅在表达式的右侧使用不受信任的数据,尤其是看起来像代码并可能传递给应用程序的数据。
在表达式左侧使用不受信任的用户数据允许攻击者破坏窗口对象的内部和外部属性,而在表达式右侧使用用户输入则不允许直接操作。
规则七:
在DOM中的URL编码时,请注意字符集的问题,因为javascript DOM中字符集没有明确定义。
规则八:
使用 object[x] 访问器时限制对对象属性的访问
使用访问器时限制对对象属性的访问(Mike Samuel)。换句话说,在不受信任的输入和指定的对象属性之间添加间接级别。
下面是使用映射类型的问题示例:
编写上述代码的开发人员试图向对象添加其他键控元素。但是,攻击者可以利用这一点来破坏对象的内部和外部属性。
更好的方法是使用以下方法:
规则九:
javascript 代码最好在沙箱环境中运行。
在沙箱中运行你的 JavaScript,使你的 JavaScript API 更难受到损害。
规则十:
不要使用eval()
用JSON相关方法 将其转换为原生 JavaScript 对象。
3、XSS 攻击后果
XSS 攻击的后果是相同的,无论它是否是 存储或反射(或基于 DOM)。这 不同之处在于有效负载到达服务器的方式。不要被愚弄 认为“只读”或“小册子”网站不是 容易受到严重的反射 XSS 攻击。XSS 会导致各种 最终用户的问题,其严重程度从烦恼到 完全帐户泄露。最严重的 XSS 攻击涉及 泄露用户的会话 cookie,允许攻击者劫持 用户的会话并接管帐户。其他破坏性攻击 包括泄露最终用户文件、安装特洛伊木马 程序,将用户重定向到其他页面或站点,或修改 内容的呈现。一个 XSS 漏洞,允许攻击者 修改新闻稿或新闻可能会影响公司的股价 或降低消费者信心。制药上的 XSS 漏洞 网站可能允许攻击者修改剂量信息,从而导致过量。
4、框架安全
在使用现代 Web 框架构建的应用程序中出现的 XSS 错误较少。这些框架引导开发人员采用良好的安全实践,并通过使用模板、自动转义等来帮助缓解 XSS。也就是说,开发人员需要注意不安全使用框架时可能出现的问题,例如:
- 框架用于直接操作 DOM 的转义舱口
- 在不清理 HTML 的情况下做出反应
dangerouslySetInnerHTML
- React 无法在没有专门验证的情况下处理 URL
javascript:
data:
- Angular 的功能
bypassSecurityTrustAs*
- 模板注入
- 过时的框架插件或组
了解您的框架如何防止 XSS 以及它存在哪些差距。有时您需要在框架提供的保护之外执行某些操作。这就是输出编码和 HTML 清理至关重要的地方。OWASP正在为React,Vue和Angular制作特定于框架的备忘单。
5、XSS 防御理念
要使 XSS 攻击成功,攻击者需要在网页中插入并执行恶意内容。需要保护 Web 应用程序中的每个变量。确保所有变量都经过验证,然后被逃逸或消毒,这被称为完美抗注入性。任何不经过此过程的变量都是潜在的弱点。框架可以轻松确保变量得到正确验证和转义或清理。
然而,框架并不完美,在React和Angular等流行框架中仍然存在安全漏洞。输出编码和 HTML 清理有助于解决这些差距。
6、XSS Payload
在黑客 XSS 攻击成功之后,攻击者能够对用户当前浏览的页面植入各种恶意脚本,通过恶意脚本来控制浏览器,这些脚本实质上就是 JavaScript
脚本(或者是其他浏览器可以运行的脚本),这种恶意植入且具有完成各种具体功能的恶意脚本就被称为 XSS Payload
。
XSS Payload 常见的可以在以下github上进行查看。GitHub - payloadbox/xss-payload-list: 🎯 跨站点脚本( XSS ) 漏洞有效负载列表https://github.com/payloadbox/xss-payload-list
7、源码扫描
前端项目在进行源码扫码的时候经常会出现关于xss的相关问题,一般扫出来的结果,基本上高危级别的漏洞,关于如何快速解决相关的漏洞,找了一大圈,发现下面这个库还算比较好用的,github地址如下所示:
GitHub - leizongmin/js-xss: Sanitize untrusted HTML (to prevent XSS) with a configuration specified by a Whitelist
它对应的官网地址是:根据白名单过滤HTML(防止XSS攻击) (jsxss.com)
示例:
var source = '<div a="1" b="2" data-a="3" data-b="4">hello</div>';
var html = xss(source, {
onIgnoreTagAttr: function (tag, name, value, isWhiteAttr) {
if (name.substr(0, 5) === 'data-') {
// 通过内置的escapeAttrValue函数来对属性值进行转义
return name + '="' + xss.escapeAttrValue(value) + '"';
}
}
});
console.log('%s\nconvert to:\n%s', source, html);
运行结果: