一、XSS漏洞的介绍
跨站脚本是一种常出现于web程序中的计算机安全漏洞,由于web应用程序对用户的输入过滤不严格导致的。攻击者利用网站漏洞,把恶意的脚本代码(通常包括html和javascript脚本)注入到网页之中。
web浏览器的设计本身就是不安全的,浏览器包含了解析和执行javascript等脚本语言的功能,但是并不会判断数据和程序代码是否为恶意数据。如果系统对输入和输出没有进行过滤,那么也会出现xss漏洞
二、xss漏洞实例
示例1:
看一段html代码
<html>
<head>test</head>
<body>
<script>alert('xss')</script>
<body>
</html>
body体内包含了一个javascript代码块,而alert()函数可以打开一个消息框,弹出函数的内容xss。我们把这个内容保存为html打开,便会有如下图显示,者也就是最基本的xss漏洞。
在html中,如果<script>
标签中间包含的是javascript,那么浏览器在处理时,就不会再将此内容处理为html或者xhtml,从这这一点开始,对于内容的控制权已经转移到了另一个内置的浏览器代理,即脚本引擎处。
xss攻击就是将攻击者想要插入的javascript代码、VBscript代码等注入到用户到网页中,而浏览器在处理javascript等语言时,只负责解析和执行,并不会对语言是否有危害进行判断。
示例2:
<html>
<head>
<title>xss测试</title>
</head>
<body>
<form action="xss.php" method="POST">
请输入名字:<br>
<input type="text" name="name" value=""></input>
<input type="submit" value="提交"></input>
</body>
</html>
以html格式打开后如下:
后台的php处理代码如下:
<html>
<head>
<title>测试结果</title>
</head>
<body>
<?php
echo $_REQUEST[name];
?>
</body>
</html>
这段代码使用$_REQUEST[name]来获取用户传入的name变量,然后使用echo进行输出。在这段代码中,输入的值为name参数,但是并没有对name参数进行任何的校验,所以我们不管输入任何内容,浏览器都会进行输出。我们输入,浏览器则会弹出一个对话框。
三、xss的分类
3.1、反射型XSS
反射型也称为非持久型、参数型跨站脚本。反射型主要用于将恶意脚本附加到URL地址的参数或者input表单中。
例如:
http://www.test.com/search.php?key"><script>alert("xss")</script>
http://www.test.com/help.shtml?query=%3Cscript%3Ealert%281%29%3C/script%3E
http://www.test.com/logoout.asp?out=1&url=javascript:alert(document.cookie)
反射型xss的利用一般是攻击者通过特定手法(比如是电子邮件),诱使用户去访问一个包含恶意代码的URL,当受害者单击这些专门设计的链接的时候,恶意javascript代码会直接在受害者主机上的浏览器上执行。他的特点是只在用户单击时触发,而且只执行一次,非持久化,所以称为反射型跨站脚本。
此类XSS通常出现在网站的搜索栏、用户登入口等地方,常用来窃取客户端cookies或进行钓鱼欺骗。
我们在第一节中演示的均为反射型跨站脚本攻击
<html>
<head>test</head>
<body>
<script>alert('xss')</script>
<body>
</html>
3.2、存储型XSS
存储型跨站脚本攻击也叫做持久型跨站脚本攻击,由于javascript等代码会上传到服务器,所以危害相比反射型会更高。
此类XSS不需要用户单独点击特定URL就能执行跨站脚本,攻击者事先将恶意的JavaScript代码上传或者存储到漏洞服务器上,只要受害者浏览包含此恶意代码的页面,就会执行恶意代码。
一般存储型出现在网站评论、留言、博客日志等交互处,恶意脚本被存储到客户端或者服务器的数据库中,当其他用户访问该页面时,站点就会从数据库中读取攻击者存入的恶意数据,然后显示在页面中,即在受害者主机上的浏览器执行恶意代码。
看一下DVWA上存储型XSS的讲解:
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = stripslashes( $message );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitize name input
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
以post方式传入两个参数mtxMessage和txtName。然后用trim()函数、stripslashes()函数对一些特定字符进行转义,删除反斜杠,移除\0、t、\n、\x0B、\r等预定义字符,但是对参数本身内容的校验作用并不大。我们写入即可。
再次访问这个页面,存储型xss验证成功。
存储型XSS和反射型XSS的区别在于:这个代码块连接了数据库,将消息存入了数据库中。
3.3、DOM型XSS
1、在学习DOM型XSS时,我们先简单了解一下什么是DOM。
DOM,即文档对象模型(Document Object Model ):它是一种与平台和语言无关的应用程序接口(API),可以动态地访问程序和脚本
,更新其内容、结构和www文档的风格(目前,HTML和XML文档是通过说明部分定义的)。文档可以进一步被处理,处理的结果可以加入到当前的页面。DOM是一种基于树的API文档,它要求在处理过程中整个文档都表示在存储器中。
2、以DVWA为例:
url地址为:http://127.0.0.1/DVWA-master/vulnerabilities/xss_d/?default=English
我们得到的有用信息就是URL中的default=English
,那这一信息如何联系到我们所说的DOM XSS呢?
这个时候我们的关注点就在于页面源代码:
if (document.location.href.indexOf("default=") >= 0) {# 判断default=""里面的值是否存在
var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
#取出default的值,并赋值给变量lang
document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
# 将lang重新写入,产生xss
document.write("<option value='' disabled='disabled'>----</option>");
#disabled这个属性规定了某个选项应该被禁用,被禁用的选项不可用,也不可点击
}
在这一段代码中,产生XSS的原因是因为使用了location.href这个属性,JS会通过调用DOM内置对象location来获得用户输入,这块我们的输入就是default=“”,然后通过DOM调用default参数,动态的输出到页面上,如果此时对default="“没有进行过滤,那么也就导致了我们通过更改default=”"参数,产生XSS,这一类通过修改我们修改参数,然后js去动态执行,DOM去调用然后动态执行导致的XSS,我们称之为DOM型XSS。
我们修改default参数为<script>alert("xss")</script>
3、现在,我们可以用一句话来概括一下DOM型XSS,通过修改DOM节点,然后javascript动态执行,导致的XSS,就是DOM型 XSS。
四、xss的危害
1、网络钓鱼,包括盗取 各类用户账号。
2、窃取用户 cookie资料,从而获取用户隐私信息,或利用用户身份进一步对网站进行操作。
3、劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志、发送电子邮件等。
4、强制弹出广告页面、刷流量等。
5、网页挂马。
6、进行恶意操作,例如篡改页面信息、删除用户数据等。
7、进行大量的客户端攻击,如DDOS攻击等。
8、获取客户端信息,例如用户的浏览历史、真实IP、开放端口等。
9、控制受害者机器向其他网站发起攻击。
10、结合其他漏洞,如csrf,实施进一步攻击。
11、提升用户权限。
12、传播跨站脚本蠕虫等。
五、xss的防御
1、输入验证
对用户输入的数据进行有效验证,仅接受指定长度的数据、适当格式的内容。
输入是否包含合法的字符;
输入字符串是否超过最大长度限制;
输入如果为数据,数字是否在有效范围内;
输入是否符合特殊的格式要求,如E-mail、IP格式等。
输入时对某些敏感字符进行过滤& # javascript expression <>等。
2、输出验证
HTMLEncode利用HTML实体替代字面量字符,如果存在恶意字符的话,可以将其作为HTML文档而非结构进行处理。
显示 | 实体名字 | 实体编号 |
---|---|---|
< | < | < |
> | > | > |
& | & | & |
" | " | " |
除了使用HTMLEncode之外,现在很多程序语言都有编码的程序库。例如:php的htmlspecialchars() 函数;Server.HTMLEncode(string) 等。 |
3、黑名单和白名单
黑名单 | 白名单 | |
---|---|---|
说明 | 过滤可能造成xss字符和标签 | 只允许规定格式的语法 |
示例 | 如使用<script>、alert 等将其转义为空 | 仅允许<img src=>通过 |
优点 | 可允许开放某些特殊的HTML标签 | 可允许特定格式的标签通过 |
缺点 | 过滤限制不足导致绕过 | 用户可输入减少 |
4、利用httponly,可以有效的防止cookie劫持攻击。
5、CSP:Content Security Policy,主要是用来定义页面可以加载哪些资源,减少XSS的发生。