攻击者利用网站漏洞把恶意的脚本代码(一般包括HTML代码和JavaScript脚本)注入到网页中,当其余用户浏览这些网页时,就会执行其中的恶意代码,对受害用户可能采起cookie窃取、会话劫持、钓鱼欺骗。javascript
发出请求时,XSS代码出如今URL中,做为输入提交到服务器端,服务器解析后响应,XSS代码随响应内容一块儿传回浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,故叫反射XSS。html
本例使用nodejs构建项目,演示反射型XSS攻击。java
首先,咱们先建立一个目录xssfilter
而且进入该目录node
$ mkdir xssfilter
$ cd xssfilter
复制代码
在该目录继续建立一个目录xss
,用于建立咱们整个的XSS攻击的模拟服务。web
$ mkdir xss
$ cd xss
复制代码
使用express框架快速搭建整个的应用服务ajax
$ express -e ./
复制代码
安装一下全部的依赖数据库
$ npm install
复制代码
看一下目录结构express
$ npm start
复制代码
访问localhost:3000
,看是否展现成功npm
接下来咱们就要开始反射型XSS的演示了json
xss:req.query.xss
复制代码
咱们在此设置一个查询的字段来获取用户在URL中写的search内容
<div class="">
<%- xss%>
</div>
复制代码
咱们在视图层展现这个内容
接下来重启一下,查看一下带有值后展现的是啥样的
由此,咱们发现,值已经展现。
接下来,咱们开始一些有攻击性的脚本
xss=<img src="null" onerror="alert(1);"/>
复制代码
打开页面发现
这是由于Chrome会自动拦截XSS攻击
咱们设置下不让浏览器对XSS拦截
res.set('X-XSS-Protection',0);
复制代码
重启服务,打开浏览咱们会看到XSS攻击成功
黑客会将一些攻击脚本在网页上经过引诱式点击植入广告、页面篡改等,典型的好比
存储型XSS与反射型XSS的差异仅在于,提交的代码会存储到服务器端(内存,数据库,文件系统等),下次调用的时候就不须要再提交XSS代码。
存储型XSS只能读取缓存或者数据库了
对用户输入的数据进行HTML Entity编码
将用户输入的不安全的内容给过滤掉
好比:
移除用户上传的DOM属性,如onerror等
移除用户上传的Style节点、Script节点、Iframe节点等
避免直接对HTML Entity解码
使用DOM Parse转换,校订不配对的DOM标签
经过构建Node服务和创建一个评论功能,实例演示XSS的攻击与预防。
如何构建Node服务我就不重复赘述了,在以前介绍反射型XSS中已经讲过,这边我依然使用这个服务来实战。
var comments = {};
复制代码
function html_encode(str){
var result = "";
if(str.length==0){
return "";
}
result = str.replace(/&/g,">");
result = result.replace(/</g,"<");
result = result.replace(/>/g,">");
result = result.replace(/\s/g," ");
result = result.replace(/\'/g,"'"); result = result.replace(/\"/g,"""); result = result.replace(/\n/g,"</br>"); return result; }; 复制代码
router.get('/comment', function(req, res, next) {
comments.v = html_encode(req.query.comment);
})
复制代码
router.get('/getComment', function(req, res, next) {
res.json({
comment:comments.v
})
})
复制代码
<textarea name="name" rows="8" cols="80" id="text">
<p>sks<img src="null" alt="" onerror="alert(1)" /></p>
</textarea>
<button type="button" name="button" id="btn">评论</button>
<button type="button" name="button" id="get">获取评论</button>
复制代码
<textarea>
用于用户输入区域
<button>
用于提交评论和拉取评论信息
经过这样,咱们就实现了一个模拟的XSS攻击
var btn = document.getElementById("btn");
var get = document.getElementById("get");
var txt = document.getElementById("text");
复制代码
btn.addEventListener("click",function(){
......
}
复制代码
var xhr = new XMLHttpRequest();
复制代码
var url = '/comment?comment='+txt.value;
复制代码
由于是get请求
在客户端向服务端发送以前,首先打开对象,告诉对象是以GET
方式打开
xhr.open('GET',url,true);
复制代码
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
if(xhr.status==200){
console.log(xhr);
}else{
console.log("error");
}
}
}
复制代码
xhr.send();
复制代码
get.addEventListener("click",function(){
......
}
复制代码
var xhr = new XMLHttpRequest();
复制代码
var url = '/getComment';
复制代码
由于是get请求
在客户端向服务端发送以前,首先打开对象,告诉对象是以GET
方式打开
xhr.open('GET',url,true);
复制代码
导入js
<script src='/public/javascripts/encode.js'></script>
<script src='/public/javascripts/domParse.js'></script>
复制代码
自行去第三方库下载
定义一个函数
var prase = function(str){
var results = '';
try{
}catch(e){
//TODO handle the exception
}finally{
}
}
复制代码
解码
HTMLParse(he.unescape(str,{strict:true}),{});
复制代码
he
是encode.js
提供的
unescape()
对输入一种反转义的过程
HTMLParse()
在反转义的基础上进行domParse,得到咱们能正常使用的结果
配对校验
start:function(tag,attrs,unary){//tag:标签;attrs:将属性组成数组;unary:是不是单标签
results += '<'+tag;
for(int i=0,len=attrs.length;i<len;i++){
results += " "+attrs[i].name+'="'+attrs[i].escaped+'"';
}
results += (unary?"/";"")+">";
},
end:function(tag){
results += "</"+tag+">";
},
chars:function(text){
results += text;
},
comment:function(text){//注释
results += "<!--"+text+"-->"
}
复制代码
查看一下完整代码
<script type="text/javascript">
var prase = function(str){
var results = '';
try{
HTMLParse(he.unescape(str,{strict:true}),{
start:function(tag,attrs,unary){//tag:标签;attrs:将属性组成数组;unary:是不是单标签
results += '<'+tag;
for(int i=0,len=attrs.length;i<len;i++){
results += " "+attrs[i].name+'="'+attrs[i].escaped+'"';
}
results += (unary?"/";"")+">";
},
end:function(tag){
results += "</"+tag+">";
},
chars:function(text){
results += text;
},
comment:function(text){//注释
results += "<!--"+text+"-->"
}
});
return results;
}catch(e){
console.log(e);
}finally{
}
}
</script>
复制代码
定义对象客户端响应方式
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
if(xhr.status==200){
var com = prase(JSON.parse(xhr.response).comment);
}else{
console.log("error");
}
}
}
复制代码
xhr.send();
复制代码
var info = document.createElement('span');
info.innerHTML(com);
document.body.appendChild(info);
复制代码
重启一下,打开浏览器
点击评论,而后再点击获取评论,来模拟浏览器加载服务端评论内容的行为
看下怎么执行的
这边有p
标签、sks
文本、img
标签,在img
标签里,有个src
属性,为null,看下控制台,报错:Failed to load resource
,所以触发了onerror
属性。
点击评论,再点击获取评论
点击攻击我
这就是引诱式攻击
到此,咱们发现,并无屏蔽掉XSS攻击,那是由于咱们并无进行过滤
if(tag=='script'||tag=='style'||tag=='link'||tag=='iframe'||tag=='frame'){
return;
}
复制代码
这个就是去过滤这些标签
把以前的代码删掉,由于这段代码就包含了那些含有XSS攻击的脚本,从而保证咱们获取信息的安全性,避免XSS脚本执行的空间。
for(int i=0,len=attrs.length;i<len;i++){
results += " "+attrs[i].name+'="'+attrs[i].escaped+'"';
}
复制代码
打开浏览器,从新操做,发现已经成功拦截了XSS攻击,看下控制台,咱们发现img
标签下的属性被自动过滤掉了。