XSS 跨站脚本攻击
- Cross-Site Scripting
跨站脚本攻击分为3种类型
1 DOM-Based
恶意的脚本只在当前的页面执行,没有存储到后台数据库中
在网页 input
或者textarea
等输入的地方注入脚本<script>alert('xss')</script>
,如果存在xss漏洞则会执行用户的恶意脚本
// 转译用户输入的内容非常重要
<body>
<input type="text" id="web">
<button id="add">添加图片</button>
<div class="box"></div>
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script>
/**
* 不基于后端 DOM-Based,修改属性 插入内容 document.write 等属性
* 直接改变结构后,造成攻击 攻击的内容 xss palyload
* <img src="xxx" onerror="alert(1)">
* 不要轻易的将src 路径的内容交给用户,如果一定交给用户转译用户的内容
* encodeURI
* */
//在input框内输入 xxx" onerror="alert(1)
$('#add').on("click", function () {
$(".box").html(`<img src="${
encodeURI($('#web').val())
}"/>`)
})
</script>
</body>
2 反射型
- 2.1 直接使用URL参数注入
// 将用户的内容直接展示在页面,用户通过修改URL 中query的参数,执行注入的恶意脚本
http://localhost:4000/api/welcome?name="<script>可执行的恶意脚本</script>"
后台代码直接对用户的url参数没有转译,直接将参数的内容返回给前端
const express = require("express");
const app = express();
const bodyParser = require('body-parser');
// body-parser是可以将用户请求的query形式的参数转换成对象
app.user(bodyParser.urlencoded({extended:true}))
app.get('/welcome',(req,res) => {
const queryParams = req.query;
const userInfo = queryParams.name;
res.send(userInfo);
})
// 此时用户在url参数修改了参数改成了恶意的脚本,所以此时页面就会展示, '可执行的恶意脚本' 中的脚本内容
app.listen(4000,(err) =>{
console.log("server is running at 4000);
})
3 存储型
- 对于用户输入的内容为恶意脚本并存储到了数据库,这样所有访问该页面的人都会执行该恶意脚本
// 1 .如用户发表评论,需要对于用户输入的内容进行转译
// 2. 在展示用户的评论信息的时候也需要转译展示用户输入的内容
function encodeHtml(str){
return str.replace(/&/g,'&')
.replace(/"/g, '"')
.replace(/'/g, '&apos')
.replace(/</g, '<')
.replace(/>/g, '>')
}
function getList(){
$.get('/api/list')
.then(res => {
if(res.code === 0) {
let str = '';
let list = res.comment;
list.forEach((item) => {
// 对接口返回的内容进行转译展示
str += `<li class="list-group-item">
${item.username}:${encodeHtml(item.comtent)}
</li>`
})
}
})
}
getList();
/**
* 用户发表评论,获取用户的内容,存储到服务器
* <script>用户的脚本内容<\/script>
* */
function addComment(e){
// 对 用户输入的评论信息进行转译
let comment = encodeHtml($('#comment').val())
if(comment && comment.trim().length > 0){
$.post('/api/addComment',{comment})
.then(res => {
if(res.code == 1){
location.href = '/public/login.html'; //// 未登录去登录页
} else{
getList()
}
})
}
}
防御手段
CSRF 跨站请求伪造
- Cross-Site Request Forgery
- 用户已登录存有cookie等用户信息 + 点击了恶意的网址,借用户的cookie用户信息调用正规网站的接口。
用户已登录+点击了恶意网址
钓鱼页面,插入调用转账的接口iframe
//钓鱼的恶意页面为
<body>
<div>
哈哈哈,赶紧找个美女脱单,(钱丢了)
</div>
<iframe src="./index.html" frameborder="0" style="display: none;"></iframe>
<!--
xsrf 简单的实现,在钓鱼页面上,插入一段 iframe, 该iframe自动引入一段正规网站的
表单请求地址,满足正常的转账接口的请求的参数以及地址,就可以每访问一次就转账一次
跨站请求伪造
-->
</body>
插入的iframe表单转账请求
<body>
<form name="myform" action="http://localhost:4000/api/transfer" method="post">
<input type="text" name="target" value="duoduo">
<input type="text" name="howmuch" value="10">
</form>
<script>
document.myform.submit()
</script>
</body>
原理;
-
- 由于用户已经登录浏览器存有用户的个人cookie信息,所以在访问钓鱼网站的时候,调用正则网站的转账接口,实际上用的是当前用户的钱
-
- 钓鱼网站通过借用用户的登录信息,然后调用正规网站的接口,实现盗用的目的。
解决方案:
1 使用验证码或者通过手机短信验证码
通过安装 svg-captcha 给用户发送一段svg验证码信息,如果用户输入的信息与验证码响匹配,则钓鱼网站无法获取到准确的验证码信息
2 #### 判断来源
- 验证HTTP Referer 字段 ,利用HTTP 头部中的Referer字段判断请求来源是否合法,Referer记录了该HTTP请求的来源地址
优点:简单易行,只需要在最后给素有安全敏感的请求统一增加一个拦截器拦截器来检查Referer的值就可以。特别是对于当前现有的系统,不需要改变当前凶弹过得任何已有代码和逻辑,没有风险,非常便捷。 缺点: Referer的值是由浏览器提供的,不可全信,低版本的浏览器下的Referer存在伪造风险。用户自己可以设置浏览器使其在发送请求时不再提供Referer时,网站将居家合法用户访问
3 加token处理
-
CSRF cross-site request forgery 能够成功是因为黑客可以完全伪造用户的请求,该请求所有的验证信息都存在于cookie中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的cookie来通过安全验证。要抵御CSRF,
关键在于请求中放入黑客所不能伪造的信息,并且该信息不存在于cookie中
。可以在http请求以参数的形式加入随机产生的token,并在服务器简历一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。 -
通常使用的方法是在每一次页面加载的时候,使用js遍历整个dom树,对于dom中素有的a和form标签加入token.这样可以解决大部分的请求,但是对于页面加载之后动态加载的html代码,这种方法就没有作用,还需要程序员在编码时手动添加token
优点:这种方法比Referer安全,token可以在用户登录后产生并放于session中,然后每次请求把token与session中拿出来,与请求中的token比对 缺点:对有的接口都加token比较困难,难以保证token本身的安全,依然会被利用取到token
- 在http头中自定义属性并验证
这种方法也是使用token并验证,和上一种方法的不同之处是,这里并不是把token以参数的形式至于HTTP请求之中,而是把它放到HTTP头自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有的该类型的请求加上csrftoken这个HTTP请求头属性,并把token值放入其中。这样解决了上种方法在请求中加入token的不便,同时通过XMLHttpRequest请求地址不会被记录在浏览器的地址栏,也不用担心token会透过Referer泄漏到其他网址中去。
优点:统一管理token输入输出,可以保证token的安全性 缺点:有局限性,无法在非异步的请求上实施。
xss + csrf = xsrf
存储型 + 执行恶意脚本请求
由于执行xss的漏洞,让恶意的脚本存储到了服务器,每次恶意脚本就会利用用户的cookie调用某些敏感的接口,这种危害是最大的
- 这种请求只要访问的用户都会被盗用用户信息以及执行恶意的脚本
完整的代码参考: gitee.com/fancylijia/…