By:Mirror王宇阳javascript
XSS攻击是指在网页中嵌入一段恶意的客户端Js脚本代码片断,JS脚本恶意代码能够获取用户的Cookie、URL跳转、内容篡改、会话劫持……等。php
xss攻击手段自己对服务端没有直接的危害,xss主要是借助网站传播;通常经过留言板、邮件、等其余途径向受害者发送一段恶意的URL,受害者经过访问该恶意URL可能会致使恶意的xss脚步会在受害者的客户端浏览器中执行,实现本身的目的html
XSS的攻击类别分为:反射型、存储型、DOM型等三大类攻击类别。前端
反射型XSS会把用户输入的数据直接返回给页面,是一种非持久型攻击;这类型的xss是最为常见的,主要的利用方法就是恶意脚本添加到参数(URL)发送给用户诱骗用户点击后反射数据给页面。java
页面源码mysql
<!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>
后台源码web
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Text page | Return</title> </head> <body> <h2>反射型测试页面</h2> <?php echo $_GET["name"]; ?> </body> </html>
源码分析sql
咱们输入的内容会被执行并嵌入在HTML页面中;$_GET['name']会触发js恶意代码并嵌入HTML页面中。数据库
测试express
XSS测试
结果发现:咱们在输入text框中写入了一个Js代码,代码直接被执行并嵌入在HTML页面中;众所周知,Js代码和HTML代码直接暴露在客户端,一旦写入的Js代码能够被执行并嵌入在HTML页面中即视为存在XSS攻击。
恶意利用
咱们经过向受害者发送以下的恶意URL就能够实如今用户客户端执行该恶意js脚本;
http://127.0.0.1/xss/xss.php?name=<script>alert('XSS测试结果');</script>
攻击者还会将URL进行各式各样的加密转换的处理,最大程度的减小URL恶意脚本的暴露;
存储型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;
HTML页面源码
<!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>
PHP后台源码
<!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>
分析
当用户在content写入一个可执行恶意js脚本的标签便可过程xss例如:<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>
分析
当咱们想id=xss提交数据后,提交的内容则会做为a标签的href属性被写入在HTML页面中;而攻击者则采用闭合拼接的方式来构成恶意的xss
测试
构造恶意的闭合xss
<a href = "" onclick=alert("Hello,World!") >超连接</a> xss 提交: " onclick=alert("Hello,World!")
这样的xss构造语句会向测试区域发送恶意的构造标签实现攻击目的
<script> alert(1) </script> <img src=x onerror = alert(1) /> <svg onload=alert(1)> <a href=javascript:alert(1)>
JS提供了四种字符编码的策略
\***
\x**
\u****
控制字符,例如 \r , \h , \t
HTML实体编码
命名实体:命名以 “&” 开头,分号结尾;参考:实体编码字符
字符编码:十进制、十六进制ASCII编码或Unicode字符编码
在线工具:http://tool.chinaz.com/tools/urlencode.aspx
线下工具:URL编码解码工具(Burp-Decoder)
使用手动检测能够最大精确化,可是对于大型的web应用是困难的是;最首要的重要就是哪里有输入、输入的结果输出的地方。
手工检测XSS要使用特殊意义的字符,这样能够快速的测试是否存在XSS;
可得知输出位置
输入一些敏感字符,例如: > < " ' ( )等,遵守自提交后查看HTML源代码,查看本身输入的字符是否被转义;
没法得知输出位置
大多的web应用时非开源的,测试XSS的时候没法得知具体的输出位置显示;例如:咱们的评论提交后会交由后台进行内容敏感检查,咱们就没法得知具体的输出位置了;
<input type="text" id="name" value="Coke" />
上述是一个表单,咱们可使用/> xxx
测试该标签的具体输出位置
Cookie时可以让网站服务器吧少许的文本数据存储到客户端的硬盘或内存中,用于维持HTTP无状态协议致使的可持续网站会话;
如何产生:
当咱们访问某网站,网站服务端因为HTTP时无状态协议,而客户端和服务器没法直接判断是否来自同一个客户源,为此当用户访问第一次网站后并登陆等操做,服务端会返回Cookie给客户端的硬盘或内存中存留
如何使用:
当用户第二次访问服务端的时候,服务端就会检查客户端中是否有Cookie文件,若是有Cookie则会利用该文件登陆并访问网站
Cookie格式:
每个浏览器保存的Cookie的文件位置均不一样,这里以Firefox浏览器为例,咱们访问DVWA平台并登陆,保存用户和密码造成Cookie
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真正的意义
利用xss获取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() 代替。
页面添加设置COOKIE
<!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>
xss获取Cookie
<script> alert(document.cookie);//获取Cookie </script>
恶意构造URL
http://127.0.0.1/xss/xss.php?name=<script>alert(document.cookie);</script>
如果用户访问了这个URL则会直接暴露本身的COOKIE,一旦暴露,攻击者能够伪造COOKIE访问。
COOKIE安全
正是由于Cookie存在客户端且能够容易被伪造,因此最初的预防办法就是高度加密;用户获取Cookie信息后伪造Cookie登陆便可操做该帐号。对于高度加密的COOKIE攻击者至于要原样伪造一个便可,由于解密的大可能是在服务端解密Cookie的;Cookie被窃取后就会致使Cookie伪造会话/Cookie欺骗严重的安全漏洞。
输入过滤
永远不要相信用户的输入;通常状况在客户端要设置字符验证过滤敏感的字符、限制长度、要求格式……等。固然客户端的内容用户都是可控的,单单依靠客户端是不可靠的,经过Burp等工具,能够轻易的修改数据包,绕过 客户端的过滤检查。
输出转码
千万不要把用户的输入内容完整的回显至HTML页面中!通常使用HTMLEncode进行编码处理。
htmlspecialchars()函数能够将部分特殊字符转出HTML实体编码。
<?php echo htmlentities($_GET["name"]); // echo $_GET["name"]; ?>
输出的转码能够预防xss脚本直接回显执行
黑名单
使用黑名单和白名单对输入的内容进行正则匹配,不符合的则不执行并取消。开发人员将敏感的关键词 、特殊字符进行黑名单设置,将一些符合条件的字符、关键词归入白名单。
前端过滤函数
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的。
PHP设置HttpOnly
修改php.ini文件,设置session.cookie_httponly =1
setcookie()函数和setrawcookie()函数的第七个参数用来作HttpOnly启动选项
setcookie('','','','','','',TRUE); setrawcookie('','','','','','',TRUE);
php代码开启HttpOnly
<?php ini_set("session.cookie_httponly",1); session_set_cookie_params(0,null,null,null,TRUE) ?>
用户在访问网站的时候为了防止恶意脚本在本身的客户端上呗执行,也能够在浏览器上安装一个插件,利用插件的功能来禁止页面的脚本执行。