By:Mirror王宇阳
XSS攻击是指在网页中嵌入一段恶意的客户端Js脚本代码片段,JS脚本恶意代码可以获取用户的Cookie、URL跳转、内容篡改、会话劫持……等。
xss攻击手段本身对服务端没有直接的危害,xss主要是借助网站传播;一般通过留言板、邮件、等其他途径向受害者发送一段恶意的URL,受害者通过访问该恶意URL可能会导致恶意的xss脚步会在受害者的客户端浏览器中执行,实现自己的目的
XSS的攻击类别分为:反射型、存储型、DOM型等三大类攻击类别。
反射型XSS会把用户输入的数据直接返回给页面,是一种非持久型攻击;这类型的xss是最为常见的,主要的利用方法就是恶意脚本添加到参数(URL)发送给用户诱骗用户点击后反射数据给页面。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XSS | 反射型</title>
</head>
<body>
<form action="xss.php" method="GET">
<h2>xss反射型注入攻击测试</h2>
<span>测试语句:</span>
<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Text page | Return</title>
</head>
<body>
<h2>反射型测试页面</h2>
<?php
echo $_GET["name"];
?>
</body>
</html>
存储型XSS是一种持久的xss攻击类别,攻击者将恶意脚本植入到服务端数据库或长期的嵌入在HTML页面中;当用户符合触发条件后就会触发Js的xss恶意脚本。
存储型的xss通常会存储在客户端或数据库中,当用户访问页面即触发xss。
存储型的xss不需要构造URL诱骗用户去点击,大大的减少暴露和增加隐秘性。
create table text(
uid int(10) not null auto_increment primary key,
title varchar(20) null,
content text(100) null
)engine=innodb default charset=utf8;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xss | 存储型</title>
</head>
<body>
<form action="xss_storage.php" method="POST">
<span>
<h2>xss|存储型测试</h2>
<h3>留言板测试</h3>
</span>
主题:<input type="text" name="title"></br>
留言:<textarea name="content">
</textarea><!-- 文本域留言 -->
<input type="submit" name="提交">
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>xss | 存储型</title>
</head>
<body>
<!-- create databases xss_text 创建数据库-->
<?php
$conn = mysqli_connect("127.0.0.1","root","root","xss_text") or die("数据库连接错误".mysqli_error());
// set names utf-8 -- 写入数据库采用的编码(utf-8)
mysqli_query($conn, 'set names utf-8');
if (isset($_POST["title"])) {
$title = $_POST["title"];
$content = $_POST["content"];
//向数据库添加 title content 两字段的内容
$sql = "INSERT INTO `xss_text`.`text` (`uid`, `title`, `content`) VALUES (NULL, '$title', '$content')";
echo $sql;
$result_1 = mysqli_query($conn,$sql);
// 页面回显/查询数据
$result_2 = mysqli_query($conn , "select * from text");
echo "<table boreder='1'><tr><td>标题</td><td>内容</td></tr>";
while($row = mysqli_fetch_array($result_2, MYSQLI_BOTH)) {
echo "<tr><td>" . $row['title']. "</td><td>" .$row['content']. "</td>";
}
echo "</table>";
echo $row['title'];
}
?>
</body>
</html>
<input type="button" value="xss" onclick="alert(xss)"/>
,提交查询后内容就会写入在数据库中,在数据库的查询结果回显至页面后就可以触发了,这里举两个例子,一个是手动触发,一个是自动加载触发。
这是写入一个input标签,鼠标点击事件可执行一个js脚本即一个弹窗。
这里是写入了一个img标签但是标签src无索引会错误error,由此触发onerror属性执行js;也可以使用其他类似于onload属性……
测试过程中发现单引号无法存入数据库,原因本小白也是半懂不懂;在sql执行的写入的时候单引号会被转义,对此可以尝试双单引号来实现最后也会以单引号的语句保存在表中。
基于DOM的XSS攻击手段,效果上和反射型XSS类似;通过修改页面的DOM节点形成XSS。
DOM规定:
<!DOCTYPE html>
<head>
<meta charset='utf-8'>
<title>xss | DOM</title>
</head>
<body>
<h1>
XSS - DOM攻击测试页面
</h1>
<script type="text/javascript">
function xss() {
var str = document.getElementById("xss").value;
document.getElementById("demo").innerHTML = "<a href = '"+str+"'>超链接</a>";
}
</script>
<div id = "demo">
测试区域
</div>
<div>
xss测试:
<input type="text" id="xss" />
<input type="button" id="a" value="提交" onclick="xss()" />
</div>
</body>
<script> alert(1) </script>
<img src=x onerror = alert(1) />
<svg onload=alert(1)>
<a href=javascript:alert(1)>
JS提供了四种字符编码的策略
\***
\x**
\u****
命名实体:命名以 “&” 开头,分号结尾;参考:实体编码字符
字符编码:十进制、十六进制ASCII编码或Unicode字符编码
在线工具:http://tool.chinaz.com/tools/urlencode.aspx
线下工具:URL编码解码工具(Burp-Decoder)
使用手动检测可以最大精确化,但是对于大型的web应用是困难的是;最首要的重要就是哪里有输入、输入的结果输出的地方。
手工检测XSS要使用特殊意义的字符,这样可以快速的测试是否存在XSS;
/> xxx
测试该标签的具体输出位置
Cookie时能够让网站服务器吧少量的文本数据存储到客户端的硬盘或内存中,用于维持HTTP无状态协议导致的可持续网站会话;
Cookie主要由变量名key和值value组成:
Set-Cookie: <name>=<value>[;<Max-Age>=<age>][;expires=<date>][;domain=<domain_name>][;path=<some_path>][;secure][;HttpOnly]
Set-Cookie
HTTP服务器的响应头,Web服务器通过此头讲Cookie发给客户端
name=value
Cookie必有部分,用户通过name取得Cookie的对应的Value值
expires=<date>
规定了Cookie的有效终止日期;缺省该字段则cookie不会存储在硬盘中
domain=<domain_name>
规定了哪些Internet域中的Web服务器可以读取客户端的Cookie文件,如果缺省则Web服务器的域名为Value;
path=<some_path>
定义Web服务器上哪些路径下的页面可以获取服务器发送的Cookie文件;Value为/
表示Web服务器中所有页面都可以获取Cookie文件;如果缺省,Path的Value则是Web服务器向客户端发送Cookie的URL;
Secure
Cookie中标明变量,只有当web服务器和客户端之间采用HTTPS加密认证协议才可以进行连接通信提交Cookie文件
HttpOnly
禁止JavaScript读取
Cookie中的内容经过加密处理,只有Web服务器的Cookie处理程序可以解析Cookie真正的意义
setcookie()
函数向客户端发送一个 HTTP cookie。参考文章setcookie(name,value,expire,path,domain,secure)
# 参数定义
name 必需。规定 cookie 的名称。
value 必需。规定 cookie 的值。
expire 可选。规定 cookie 的有效期。 若是删除一个cookie则可以设置时间为过去时
path 可选。规定 cookie 的服务器路径。
domain 可选。规定 cookie 的域名。
secure 可选。规定是否通过安全的 HTTPS 连接来传输 cookie。
注释:可以通过 $HTTP_COOKIE_VARS["user"] 或 $_COOKIE["user"] 来访问名为 "user" 的 cookie 的值。
注释:在发送 cookie 时,cookie 的值会自动进行 URL 编码。接收时会进行 URL 解码。如果你不需要这样,可以使用 setrawcookie() 代替。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>XSS | 反射型</title>
</head>
<body>
<form action="xss.php" method="GET">
<h2>xss反射型注入攻击测试</h2>
<span>测试语句:</span>
<input type="text" name="name">
<input type="submit" value="提交">
</form>
<?php
$COOKIE="XSS获取COOKIE测试";
setcookie("xss_cookie",$COOKIE);
echo "COOKIE设置成功";
?>
</body>
</html>
<script>
alert(document.cookie);//获取Cookie
</script>
<?php
echo htmlentities($_GET["name"]);
// echo $_GET["name"];
?>
function xss_clean($data){
// Fix &entity\n;
$data=str_replace(array('&','<','>'),array('&','<','>'),$data);
$data=preg_replace('/(&#*\w+)[\x00-\x20]+;/u','$1;',$data);
$data=preg_replace('/(&#x*[0-9A-F]+);*/iu','$1;',$data);
$data=html_entity_decode($data,ENT_COMPAT,'UTF-8');
// Remove any attribute starting with "on" or xmlns
$data=preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu','$1>',$data);
// Remove javascript: and vbscript: protocols
$data=preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2nojavascript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2novbscript...',$data);
$data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u','$1=$2nomozbinding...',$data);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i','$1>',$data);
$data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu','$1>',$data);
// Remove namespaced elements (we do not need them)
$data=preg_replace('#</*\w+:\w[^>]*+>#i','',$data);
do{// Remove really unwanted tags
$old_data=$data;
$data=preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i','',$data);
}while($old_data!==$data);
// we are done...
return $data;
}
<?php
//php防注入和XSS攻击通用过滤.
//by qq:831937
$_GET && SafeFilter($_GET);
$_POST && SafeFilter($_POST);
$_COOKIE && SafeFilter($_COOKIE);
function SafeFilter (&$arr)
{
$ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/','/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/','/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/','/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/','/onmouseout/','/onmouseover/','/onmouseup/','/onunload/');
if (is_array($arr))
{
foreach ($arr as $key => $value)
{
if (!is_array($value))
{
if (!get_magic_quotes_gpc())//不对magic_quotes_gpc转义过的字符使用addslashes(),避免双重转义。
{
$value = addslashes($value); //给单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)加上反斜线转义
}
$value = preg_replace($ra,'',$value); //删除非打印字符,粗暴式过滤xss可疑字符串
$arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 标记并转换为HTML实体
}
else
{
SafeFilter($arr[$key]);
}
}
}
}
?>
防止xss窃取Cookie可以使用HttpOnlyCookie;
当一个Cookie在Set-cookie消息头中被标明为HttpOnly时,客户端的js是不可以直接访问该cookie的。
session.cookie_httponly =1
setcookie('','','','','','',TRUE);
setrawcookie('','','','','','',TRUE);
<?php
ini_set("session.cookie_httponly",1);
session_set_cookie_params(0,null,null,null,TRUE)
?>
用户在访问网站的时候为了防止恶意脚本在自己的客户端上呗执行,也可以在浏览器上安装一个插件,利用插件的功能来禁止页面的脚本执行。