XSS漏洞是什么,常见的XSS漏洞(非常详细)
跨站脚本(Cross-Site Scripting,XSS)是经常出现在 Web 应用程序中的一种计算机安全漏洞。
XSS 主要是由于 Web 应用程序对输入和输出过滤不足而产生的。攻击者可以利用这一漏洞把恶意的脚本代码(通常包括 HTML 代码和客户端 JavaScript 脚本)注入网页中。当其他用户浏览这些网页时,这些恶意代码就会被执行,进而进行 Cookie 信息窃取、会话劫持、钓鱼欺骗等各种攻击。
利用反射型 XSS 漏洞攻击的流程如下图所示:

图 1 利用反射型XSS漏洞攻击的流程
此类 XSS 漏洞通常出现在网站的搜索栏、用户登入口等地方,常用来窃取客户端 Cookie 或进行钓鱼欺骗。
下面是导致反射型 XSS 漏洞的示例代码:
正常访问 http://localhost:8080/reflective-xss.jsp?id=111,结果如下:
从示例代码中可以看到,输出语句没有进行任何过滤就直接把用户的输入内容给输出了,因此可以构造如下恶意链接:http://localhost:8080/reflective-xss.jsp?id=<script>alert("xss")</script>。
当目标用户访问该链接时,服务器接受该目标用户的请求并进行处理,然后服务器把带有 XSS恶意代码的脚本发送给目标用户的浏览器,浏览器解析这段脚本后,就会触发反射型XSS漏洞。
访问恶意链接的结果如下图所示。

图 2 访问恶意链接的结果
反射型 XSS 漏洞须构造恶意 URL 来诱导用户点击,而存储型 XSS 漏洞由于有效载荷已直接被写入服务器中,且不需要将有效载荷输入到 URL 中,往往可以伪装成正常页面,其迷惑性更强。因此,存储型 XSS 漏洞对于普通用户而言很难及时被发现。
利用存储型 XSS 漏洞攻击的流程如下图所示:

图 3 利用存储型XSS漏洞攻击的流程
下面是导致存储型 XSS 漏洞的示例代码:
正常访问 http://localhost:8080/storage-xss.jsp,结果如下:
下图所示为将恶意脚本存储到服务器的数据库中:

图 4 将恶意脚本存储到服务器数据库中
当其他用户浏览该页面时,站点即从数据库中读取恶意脚本,然后显示在页面中,如下图所示:

图 5 利用存储型XSS漏洞成功攻击
DOM 是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问或更新文档内容、结构和样式,处理后的结果能够直接显示在网页上。DOM 中有很多对象,其中一些是用户可以操控的,如 URL、location、referer 等。客户端的脚本程序无须依赖服务器,即可通过 DOM 动态地检查和修改页面内容。因此如果 DOM 中的数据没有经过严格确认,就会引发 DOM 型 XSS 漏洞。
下面是导致 DOM 型 XSS 漏洞的示例代码:
通过浏览器访问构造的恶意 Poc 链接(http://localhost:8080/DOM-xss.html#1;alert(/xss/))即可触发 DOM 型 XSS 漏洞,访问结果如下图所示:

图 6 访问http://localhost:8080/DOM-xss.html#1;alert(/xss/)的结果
DOM 型 XSS 漏洞常见的输入点和输出点如下。
输入点:
输出点:
因此,在对 Java 代码进行审计以挖掘 XSS 漏洞时,需要收集所有的输入点和输出点,并仔细检查输入点和输出点的上下文环境,判断 Web 应用程序是否对输入点和输出点做了过滤、扰乱或编码等工作。
在往 JavaScript 代码中插入数据时,只有一种情况是安全的,即对不可信数据进行 JavaScript 编码,并且只把这些数据放到使用引号括起来的值(data value)中。
XSS 主要是由于 Web 应用程序对输入和输出过滤不足而产生的。攻击者可以利用这一漏洞把恶意的脚本代码(通常包括 HTML 代码和客户端 JavaScript 脚本)注入网页中。当其他用户浏览这些网页时,这些恶意代码就会被执行,进而进行 Cookie 信息窃取、会话劫持、钓鱼欺骗等各种攻击。
常见的XSS漏洞
XSS 漏洞大概可以分为 3 个类型:反射型 XSS 漏洞、存储型 XSS 漏洞和 DOM 型 XSS 漏洞。本节主要介绍这些漏洞产生的形式。1) 反射型XSS漏洞
反射型 XSS 漏洞的利用一般是攻击者通过特定手段(如利用电子邮件),诱惑用户去访问一个包含恶意代码的URL。当用户点击这些专门设计的链接时,恶意 JavaScript 代码会直接在用户的主机上执行。这种类型的XSS 漏洞的特点是只在用户点击时触发,而且只执行一次,非持久化。利用反射型 XSS 漏洞攻击的流程如下图所示:

图 1 利用反射型XSS漏洞攻击的流程
此类 XSS 漏洞通常出现在网站的搜索栏、用户登入口等地方,常用来窃取客户端 Cookie 或进行钓鱼欺骗。
下面是导致反射型 XSS 漏洞的示例代码:
<% String id = request.getParameter("id"); out.println("id = "+id); %>
正常访问 http://localhost:8080/reflective-xss.jsp?id=111,结果如下:
id = 111
从示例代码中可以看到,输出语句没有进行任何过滤就直接把用户的输入内容给输出了,因此可以构造如下恶意链接:http://localhost:8080/reflective-xss.jsp?id=<script>alert("xss")</script>。
当目标用户访问该链接时,服务器接受该目标用户的请求并进行处理,然后服务器把带有 XSS恶意代码的脚本发送给目标用户的浏览器,浏览器解析这段脚本后,就会触发反射型XSS漏洞。
访问恶意链接的结果如下图所示。

图 2 访问恶意链接的结果
2) 存储型XSS漏洞
存储型 XSS 漏洞和反射型 XSS 漏洞的原理是一样的,区别在于存储型 XSS 漏洞会把恶意脚本存储在服务器,每次访问内容都会有触发恶意脚本的可能,所以相比反射型 XSS 漏洞,存储型 XSS 漏洞的危害更大。反射型 XSS 漏洞须构造恶意 URL 来诱导用户点击,而存储型 XSS 漏洞由于有效载荷已直接被写入服务器中,且不需要将有效载荷输入到 URL 中,往往可以伪装成正常页面,其迷惑性更强。因此,存储型 XSS 漏洞对于普通用户而言很难及时被发现。
利用存储型 XSS 漏洞攻击的流程如下图所示:

图 3 利用存储型XSS漏洞攻击的流程
下面是导致存储型 XSS 漏洞的示例代码:
<%@ page import="java.sql.*" %> <% String url = "jdbc:mysql://localhost:3306/test1"; String user = "root"; String password = "root"; Connection conn = null; Statement statement = null; ResultSet resultSet = null; Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(url,user,password); statement = conn.createStatement(); String sqlQuery = "select * from message"; resultSet = statement.executeQuery(sqlQuery); while(resultSet.next()){ out.println("name: " + resultSet.getString("name")); } %>
正常访问 http://localhost:8080/storage-xss.jsp,结果如下:
name: 111
下图所示为将恶意脚本存储到服务器的数据库中:

图 4 将恶意脚本存储到服务器数据库中
当其他用户浏览该页面时,站点即从数据库中读取恶意脚本,然后显示在页面中,如下图所示:

图 5 利用存储型XSS漏洞成功攻击
3) DOM型XSS漏洞
DOM 型 XSS 漏洞是基于 Document Object Model(文档对象模型)的一种 XSS 漏洞。DOM 是一个与平台、编程语言无关的接口,它允许程序或脚本动态地访问或更新文档内容、结构和样式,处理后的结果能够直接显示在网页上。DOM 中有很多对象,其中一些是用户可以操控的,如 URL、location、referer 等。客户端的脚本程序无须依赖服务器,即可通过 DOM 动态地检查和修改页面内容。因此如果 DOM 中的数据没有经过严格确认,就会引发 DOM 型 XSS 漏洞。
下面是导致 DOM 型 XSS 漏洞的示例代码:
<script> var pos = document.URL.indexOf("#")+1; var name = document.URL.substring(pos, document.URL.length); document.write(name); eval("var a = " + name); </script>
通过浏览器访问构造的恶意 Poc 链接(http://localhost:8080/DOM-xss.html#1;alert(/xss/))即可触发 DOM 型 XSS 漏洞,访问结果如下图所示:

图 6 访问http://localhost:8080/DOM-xss.html#1;alert(/xss/)的结果
DOM 型 XSS 漏洞常见的输入点和输出点如下。
输入点:
document.URL
document.location
document.referer
document.forms
输出点:
eval
document.write
document.innerHTML
document.outerHTML
XSS漏洞代码审计要点
根据前面的内容可知,XSS 漏洞是由于 Web 应用程序对输入和输出过滤不足而产生的。从 Web 应用程序来看,攻击者可以操控的参数包括 URL、POST 提交的表单数据,以及通过搜索框提交的搜索关键字。因此,在对 Java 代码进行审计以挖掘 XSS 漏洞时,需要收集所有的输入点和输出点,并仔细检查输入点和输出点的上下文环境,判断 Web 应用程序是否对输入点和输出点做了过滤、扰乱或编码等工作。
XSS漏洞的防御方法
XSS 漏洞防御的总体思路是:对输入进行过滤,对输出进行编码。1) 使用 XSS Filter
使用 XSS Filter 对用户提交的信息进行严格验证,仅接受指定长度范围内且格式合适的信息,阻止或忽略此外的其他任何信息。此外,还需要过滤和净化有害的输入信息。2) 使用编码
HTML 编码在防御利用 XSS 漏洞进行攻击时可以起到很大的作用,它主要是用对应的 HTML 实体替代字面量字符,来确保浏览器能够安全地处理可能存在的恶意字符,并将其视为 HTML 文档的内容而非结构元素。3) 对不可信数据进行JavaScript编码
此方法主要针对动态生成的 JavaScript 代码,包括脚本部分以及 HTML 标签的事件处理属性(如 onerror、onload等)。在往 JavaScript 代码中插入数据时,只有一种情况是安全的,即对不可信数据进行 JavaScript 编码,并且只把这些数据放到使用引号括起来的值(data value)中。