浅谈XSS和CSRF

浅谈XSS与CSRF

一、XSS

1.什么是XSS攻击
XSS也叫CSS,是Cross Site Script的简称,为了和CSS(样式)区分开来,所以改名为XSS。XSS是web常见的攻击手段之一,是通过向目标网站注入可执行的恶意代码,以达到攻击的目的。黑客能够通过XSS攻击,窃取用户的信息想要进行XSS攻击,盗取用户的登陆凭证发起CSRF攻击。想要达到XSS攻击必须达到两个条件,第一是向目标网站注入恶意代码,第二是这部分代码是可以被客户端浏览器执行的。从攻击的方式划分,XSS攻击又分为反射型XSS和持久型XSS。

2.反射型XSS:
反射型XSS,是用户点击恶意链接,服务器接收解析响应后,在返回的响应中包含恶意的代码,被客户端浏览器执行,这样一来,XSS的攻击代码,是通过服务器的响应反射回来的,所以被称为反射型XSS攻击。一般攻击者会在邮件,聊天记录,钓鱼网站中添加恶意的URL,用户在不知情的情况下点击,就很容易发生XSS反射攻击。
比如:

<div>
    <img id="img1" src="~/StaticFiles/Backend/Images/@Request.QueryString["Id"].ToString()" />
</div>

在这里插入图片描述
单从源码中看,这是一个正常的页面,每次当页面加载的时候,会读取QueryString的值,加载相应的图片。但是黑客往往就会利用这个安全漏洞,在钓鱼网站,邮件,贴吧中发出一个恶意链接:

http://localhost:7286/Home/Test?Id=default_user.jpg“/><script>console.log(/xss/)<script/>

用户在不知情的情况下,点击了这个恶意链接,则浏览器会执行这一段脚本:

<script>console.log(/xss/)<script/>

用户在不知情的情况下就已经遭受到XSS攻击。

3. 持久型XSS
持久型XSS,持久型XSS具有较强的隐秘性和持久性,攻击者通常通过在博客,论坛等社交网站评论内容,将恶意的代码保存到web服务器中,当用户加载页面内容时,客户端浏览器会加载并执行这部分恶意代码。持久型XSS具有两个特点:一是恶意代码保存到了web服务器中,二是攻击者一般是利用博客,论坛等社交网站中评论留言功能,将恶意代码注入到web服务器。比起反射型XSS,持久型XSS的隐秘性更强,而且每当用户浏览论坛,博客的评论或留言时,就会受到XSS攻击,攻击范围非常广。

比如:
黑客会在评论留言中添加这么一串代码:

<script>console.log(XSS)</script>

每当用户加载评论区中的内容时,就会将这部分的恶意代码加载到客户端的浏览器中,并能够成功执行,这时,用户在不知道的情况下,就遭受到了XSS攻击。可以看出,持久型XSS具有很强的隐秘性,用户在刷博客,刷论坛的时候,不知不觉可能就已经被攻击了,而且这种攻击的范围非常的广泛,并不是只针对某一用户。

4. XSS攻击能够诱发CSRF攻击
为什么XSS攻击能够诱发CSRF攻击呢?(什么是CSRF攻击?本文后面会详细讲解。)原理很简单,上面我们说过了,XSS攻击是将恶意的代码注入带我们的网站中,那么用户在不知情的情况下,攻击者则可以通过document.cookie这个脚本,将我们的cookie发到黑客的指定网站,当黑客窃取到我们当前的登陆凭据(cookie)后,会以我们的用户身份做一个伪造请求,登陆我们的网站,做一系列的违规操作,窃取我们的数据。

5. 如何防御XSS攻击:

  1. 想要进行XSS防御,就是要对用户输入的内容,请求URL和web服务端返回给浏览器的内容进行过滤转译。
    比如:
<“ 转成 ”&lt;”
”>“ 转成 ”&gt;"&” 转成 "&amp;"
\" 转成 "&quot;"
“'” 转成 "&#39"
“\” 转成 “\\”
“/” 转成 "\/"
  1. XSS一般是通过脚本(document.cookie)获取浏览器的cookie,那么如果我们在服务端将cookie的HttpOnly属性设置成true,则在客户端中,黑客就无法通过js脚本获取到我们的cookie,但是在每次请求的时候,cookie又会以请求头的形式,能够被服务器访问,不会影响到正常的使用。
    以C#为例,如果设置cookie的HttpOnly属性为true,
var cookie = new HttpCookie("username", "lyq");
cookie.HttpOnly=true;

但是将cookie的HttpOnly属性设置成true也不是万无一失的方法,因为在低版本的浏览器中,是不支持HttpOnly属性的。

二、CSRF

1. 什么是CSRF攻击?
CSRF是跨站请求伪造(Cross Site Request Forgery)的简称,是通过盗取客户端用户的合法登陆凭据,冒用了用户的合法身份,对服务器发起请求,但是这种请求对服务器来说又是合法合理的。比如:黑客能够盗用我们的合法身份,对他们的博客进行关注,评论,也能够向他们的银行账户转账。用户被攻击,首先要具备两个条件:一是用户成功登陆A网站,并且没有登出,在客户端浏览器保留了登陆凭据(cookie),二是用相同的浏览器访问恶意的网站。

2. CSRF攻击的原理:

  1. 用户lyq登陆了A网站,服务器在接收到请求后,会在服务端存放一个session,并响应客户端一个cookie,这就在用户lyq电脑的客户端保留了一个合法的登陆凭据。

  2. 用户lyq在保留了A网站的登陆凭据的前提下,用相同的浏览器访问了B网站(恶意的钓鱼网站)

  3. B网站盗取到了A网站的登陆凭据,则黑客可以利用lyq的登陆凭据,成功的访问了A网站,并且窃取到了用户LYQ的信息,做一系列的违规操作。

3.实例分析:
现在A网站是通过这么一个接口向可以向某人转账:

 http://www.lyq.com:5002/Home/TransferMoney?transferTo=someone&money=100

碰巧lyq在A网站有一个账户。某天,lyq登陆了A网站。正常情况下,lyq登陆A网站后,会在服务器内存中存放一个session, 并且服务器会响应一个cookie给客户端浏览器,作为登陆凭据。
在这里插入图片描述
粗心大意的lyq在没有登出A网站的情况下(登陆凭据没有注销),用相同的浏览器访问了B网站。

http://www.hacker.com:5003/

B网站是一个钓鱼网站。在B网站中有这么一串代码。

<iframe src="http://www.lyq.com:5002/Home/TransferMoney?transferTo=Jack&money=1000"></iframe>

当lyq访问B网站时,黑客Jack在lyq不知情的情况下,就盗用了lyq的登陆凭据,仿造lyq的请求,向A网站发送了一个转账的请求。服务器在接收到这个请求后,后认为这就是lyq自己发起的请求,认为是一个合法的请求,这就将lyq账户中的1000元转到黑客Jack的账户下。
在这里插入图片描述
由于iframe的src属性,B网站跨站的调用了A网站的转账接口,B网站发起的转账请求和A网站在客户端存留的cookie在同一个域下,则B网站每次向A网站服务器请求的时候,都会自动带上这个合法的登陆凭据(cookie),伪造成一个合法的请求。
知道这个安全漏洞后,A网站的工作人员迅速修复了这么一个安全漏洞,将这个接口设置成post请求。但是道高一尺,魔高一丈。黑客Jack也迅速对B网站做了升级。

<form action="http://www.lyq.com:5002/Home/TransferMoney" method="post" id="form1">
    <input type="text" name="transferTo" value="Jack" />
    <input type="text" name="money" value="1000" />
    <button type="submit" id="btnSubmit">提交</button>
</form>

<script>
    window.onload = function () {
        document.getElementById("form1").submit();
    }
</script>

当lyq访问到B网站时,同样会对A网站发送一个合理post请求,将lyq账户中的前转到黑客jack的帐下。当然,为了增加B网站的隐秘性,还可以下B网站下面再次嵌套一个ifram,防止页面的刷新。

4. 那如何能做到有效的防御CSRF攻击呢?

  1. 对于敏感的请求,尽量使用post请求代替get请求。这样会增加CSRF攻击的难度,从一定程度上能避免CSRF攻击。

  2. 对于表单请求,可以加上一个验证码。客户端在每次请求时,都要带上这个验证码,和服务器上的验证码进行匹配,如果匹配失败,则请求无效。这样能够有效的避免90% 以上的CSRF攻击。但是这样缺点也十分的明显,若对于一个项目来说,有很多的表单请求,如果每一个表单请求都要用验证码验证,对于用户来说会是一个很糟糕的体验。

  3. 服务器在每次接收http请求时,先判断这个http请求的来源地址Refer。如果这个http请求不是从受信任的域名发起的,我们则认为这是一个非法的请求。
    在这里插入图片描述
    以 ASP.NET MVC为例:

public void OnActionExecuting(ActionExecutingContext filterContext)
       {        
           //获取受信任域名        
           var TrustedDomain = Initialize.GetTrustedDomain;
           var httpContext = filterContext.HttpContext;                     

           if (httpContext.Request.UrlReferrer != null && !TrustedDomain.Contains(httpContext.Request.UrlReferrer.Host))
           {
               if (httpContext.Request.IsAjaxRequest())
               {
                   filterContext.Result = new JsonResult()
                   {
                       Data = new JsonData() { Info = $"403 Forbidden.", Status = "403" },
                       JsonRequestBehavior = JsonRequestBehavior.AllowGet
                   };
               }
               else filterContext.Result = new RedirectResult("/Error/NotFound");
           }
       }

但是缺点就是依赖于浏览器的Refer属性,如果用户关闭掉客户端浏览器的这一功能后,则正常的用户每次访问网站时,都会被视为一个非法的请求,无法正常使用。

  1. 一般我们现在的web应用程序,都是用Ajax做无刷新访问的,因此我们可以利用XmlHttpRequest对象。当我们每次向服务器发起请求时,服务器接收并完成时,可以客户端响应一个新的token,这时候通过Ajax的XmlHttpRequest对象,我们可以获取到这个token,在下一次的请求时,将这个token放到请求的请求头中,下次服务器在接收请求时,就会判断请求Header的token是否有效,判断这是否时一个有效的请求。但是这样的缺点时局限性很多,对于请求地址来说,很难在请求头写入token。
    因此,我们也可以将token放到请求地址中,方便我们接收。(什么是token,请看ASP.NET MV使用JWT代替session,实现单点登陆
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章