跨域访问

来源:互联网 发布:2016星火英语听力软件 编辑:程序博客网 时间:2024/06/14 07:14

同源策略 (http://baike.baidu.com/view/3747010.htm)-是针对浏览器所设计的一项安全规定,页面中 所渲染的资源(JavaScript脚本除外)都需要符合同源策略才能够正常访问。 在构建 Web 项目或者进行 XSS 攻击,CSRF攻击时,常常需要进行跨域资源访问。设想这样一个场景:攻击者 Attacker 在网站 A 上注入了一段恶意 JS 代码,用来盗取访问者的浏览器、Cookie、IP 等信息,并通过 ajax 请求将这些信息以参数的形式(GET、POST 皆可)发送至攻击者事先准备好的服务站 B 上。若按同 源策略规定,在网站 A 上不能直接请求或者发送数据至网站 B,那么这里就要用到一些跨域资源请求的 方法。 通过总结已公开的跨域方法并结合自己的理解和实践,将几种跨域资源请求的方法通过实例 Demo 的形 式详细记录如下。

CSRF攻击如下图:(简单的可以理解为:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。)


跨域网络访问:

同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest<img> 标签时则会受到同源策略的约束。交互通常分为三类:

  • 通常允许进行跨域写操作(Cross-origin writes)。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。
  • 通常允许跨域资源嵌入(Cross-origin embedding)。之后下面会举例说明。
  • 通常不允许跨域读操作(Cross-origin reads)。但常可以通过内嵌资源来巧妙的进行读取访问。例如可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或availability of an embedded resource.

以下是一些可以跨域内嵌的资源示例:

  • <script src="..."></script>标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
  •  <link rel="stylesheet" href="...">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。不同浏览器有不同的限制: IEFirefoxChromeSafari (跳至CVE-2010-0051)部分 和 Opera。
  •  <img>嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...
  •  <video><audio>嵌入多媒体资源。
  •  <object><embed> 和 <applet>的插件。
  • @font-face引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
  •  <frame> 和 <iframe>载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。

跨域脚本API访问

Javascript的APIs中,如 iframe.contentWindow,window.parent, window.openwindow.opener 允许文档间直接相互引用。当两个文档的源不同时,这些引用方式将对 Window 和 Location对象的访问添加限制。可以使用window.postMessage 作为替代方案,提供跨域文档间的通讯。

跨域数据存储访问

存储在浏览器中的数据,如localStorage和IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。

window.name属性可以用来临时存储数据,可以跨域访问。

Cookies使用不同的源定义方式。一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。Firefox和Chrome使用Public Suffix List决定一个域是否是一个公共后缀(public suffix)。不管使用哪个协议(HTTP/HTTPS)或端口号,浏览器都允许给定的域以及其任何子域名(sub-domains)来访问cookie。设置cookie时,你可以使用Domain,Path,Secure,和Http-Only标记来限定其访问性。读取cookie时,不会知晓它的出处。尽管使用安全的https连接,任何可见的cookie都是使用不安全的连接设置的。

实现跨域访问方式可分为两种:前台的和后台的。

前台有:1同主域名下iframe控制document.domain进行跨域

2. iframe集合location.hash进行跨域数据获取

3. 通过iframe.name跨域传递数据

4. 将数据通过 JS 进行直接加载

5. html5中的postMessage

6. 利用 CORS 进行跨域

后台:代理服务(Proxy)

下面详细讲前台每种实现方法:

(1)同主域名下iframe控制document.domain进行跨域

a.0xfa.club ==> 192.168.130.200(网站 A)b.0xfa.club ==> 192.168.130.200(网站 B)

事先设置域名解析情况如下(192.168.130.200为本地虚拟机): 

网站 B 上有一资源文件 data.html,其 URL 为 http://b.0xfa.club/data.html,内容如下: 

<p id="data">Hello A Site!!</p>
如果网站 A 想要获取 id="data" 的文本值 Hello A Site!!,在不考虑同源策略的情况下可以有如下代码:

<html><head> <title>a.0xfa.club/in.html</title> </head> <body> <script>      var iframe = document.createElement('iframe');    iframe.src = 'http://b.0xfa.club/location/data.html';      iframe.style.display = 'none';    iframe.onload = function() {    var doc = iframe.contentDocument || iframe.contentWindow.document;    console.log(doc.getElementById('data').textContent);    }   document.body.appendChild(iframe); </script> </body></html>

但是实际访问情况下,由于浏览器的同源策略限制,并不能成功获取数据并通过调试终端输出数据,浏 览器一般会在终端下输出错误,提示跨域访问失败。(此处为 Chrome



这时候,由于网站 A 和 B 都属于 0xfa.club 的子域,加上网站 B 可控,设置网站 document.domain 为统一主域 0xfa.club 即可进行跨域访问,完整的代码示例如下:

http://a.0xfa.club/in.html 源码:

<html><head>  <title>a.0xfa.club/in.html</title></head><body><script>document.domain = '0xfa.club';var iframe = document.createElement('iframe');iframe.src = 'http://b.0xfa.club/location/data.html';iframe.style.display = 'none';iframe.onload = function() {var doc = iframe.contentDocument || iframe.contentWindow.document;  console.log(doc.getElementById('data').textContent);}document.body.appendChild(iframe);</script></body></html>
http://b.0xfa.club/data.html 源码:

<script>document.domain = '0xfa.club';</script><p id="data">Hello A Site!!</p>

通过设置双方网站 document.domain 为同一主域,再次访问后,可以看到在访问 http://a.0xfa.club/in. html 页面时,成功获取 http://b.0xfa.club/data.html 中的数据并在调试窗口打印出来。

附注:使用document.domain来让子域安全地访问其父域,需要同时将子域和父域的document.domain设置为相同的值。必须要这么做,即使是简单的将父域设置为其原来的值。没有这么做的话可能导致授权错误。


(2)iframe结合location.hash进行跨域数据获取

利用location.hash的变化来传递数据相对来说比较复杂,IE 和 Chrome 的安全机制无法在页面上直接 更改父级窗口的 location.hash 值。在网站 A 的页面上创建了 iframe 来加载 网站 B 的页面内容,由于 同源策略的关系和浏览器安全机制的关系,网站 B 的JS 脚本不能通过直接修改 parent.location.hash, 因为其不同源。 但是,若再在网站 B 上创建 iframe 加载网站 A 上的一个代理页面,代理页面通过访问 parent.parent ,因为代理页面和网站 A 同源,自然而然就能够修改 parent.parent.location.hash 的值了,Demo 代码 如下。 

http://a.0xfa.club/hash/in.html 源码:

<html><head>  <title>Site A</title></head><body><script>var iframe = document.createElement('iframe');iframe.style.display = 'none';iframe.src = 'http://b.0xfa.club/hash/data.html#param';document.body.appendChild(iframe);var checkOut = function() {try {var data = location.hash ? location.hash.substring(1) : '';//返回url中的hash(#后面跟的字符),并去掉开头的#号if (console.log) {console.log('new data is: ' + data);}  } catch(e) {}}setInterval(checkOut, 2000);</script></body></html>

http://b.0xfa.club/hash/data.html 源码:

<html><head>  <title>Site B</title></head><body><script>try {parent.location.hash = 'bsitedata';} catch(e) {var ifr = document.createElement('iframe');ifr.style.display = 'none';ifr.src = 'http://a.0xfa.club/hash/proxy.html#bsitedata';document.body.appendChild(ifr);}</script></body></html>

http://a.0xfa.club/hash/proxy.html 源码:

<script>parent.parent.location.hash = self.location.hash.substring(1);</script>

现在访问 http://a.0xfa.club/hash/in.html 页面时,网站 B 成功的修改了 location.hash 值并被网站 A 捕获,通过调试窗口打印出来

(3)通过iframe.name跨域传递数据
浏览器中的跨域资源请求 http://rickgray.me/2015/09/03/solutions-to-cross-domain-...
由于 iframe 加载后页面可以动态修改其 contentWindow.location 来使得本来不同源的情况下变得同源, 而若网站 A 在加载网站 B 的页面 data.html 时,data.html 中设置了 window.name 的值,那么在网站 A 上通过修改 iframe.contentWindow.location 的值使得同源,然后就成功获取到网站 B 传递通过 window.n ame 传递过来的数据。 http://a.0xfa.club/name/in.html 源码:

<html><head>  <title>a.0xfa.club/name/in.html</title></head><body><script>var state = 0;var iframe = document.createElement('iframe');iframe.src = 'http://b.0xfa.club/name/data.html';iframe.style.display = 'none';var loadfn = function() {if (state === 1) {var data = iframe.contentWindow.name;console.log(data);} else if (state === 0) {state = 1;iframe.contentWindow.location = 'http://a.0xfa.club';}}iframe.onload = loadfn;document.body.appendChild(iframe);</script></body></html>
http://b.0xfa.club/name/data.html 源码:

<script>window.name = 'content of "b.0xfa.club"';</script>

访问网站 A 的页面 http://a.0xfa.club/name/in.html,页面动态创建 iframe 加载网站 B 的资源 http:/ /b.0xfa.club/name/data.html,而网站 B 的页面将需要传递的数据通过 window.name 进行设置。待动态创 建的 iframe 加载完毕后,网站 A 的页面再通过更改 iframe.contentWindow.location 来使得加载的内容 符合同源策略,但是此时的 iframe 框的 window.name 值已经被网站 B 上的页面设置过了,所以其值会 被设置为 content of "b.0xfa.club"。

(4)将数据通过JS进行直接加载

因为页面可以外部加载 JS 的原因,因此不同源的两个站点可以通过 JS 来进行跨域传递数据。 (这个很好理解,引用框架的时候经常这样做。)

http://a.0xfa.club/script/in.html 源码:

<script src="http://b.0xfa.club/script/data.html" id="p"></script><script>console.log(data);</script>

(5)html5中的postMessage

html5 中提供了一个安全跨域传输的 API - postMessage (详细文档 (https://developer.mozilla.org/e n-US/docs/Web/API/Window/postMessage)),通过使用 postMessage 可以直接设置 Origin,来达 到同源的作用。

http://a.0xfa.club/html5/in.html 源码:

<html><head>  <title>Html5 postMessage</title></head><body><iframe id="ai" src="http://b.0xfa.club/html5/data.html"></iframe><script>function changeColor() {var ifr = document.getElementById('ai');var targetOrigin = 'http://b.0xfa.club';ifr.contentWindow.postMessage('rgb(0, 255, 0)', targetOrigin);}</script><a href="#" onclick="changeColor()">Click here to change "iframe" color</a></body></html>

http://b.0xfa.club/html5/data.html 源码:

<html><head>  <title>Site B</title>  <style>  body {    background-color: rgb(255, 0, 0);  }  </style><body><script>window.addEventListener('message', function() {document.body.style.backgroundColor = event.data;console.log(event.data);});</script></script></body></html>

这里网站 A 的页面通过向内嵌的网站 B 的页面发送新的背景颜色值,网站 B 页面收到新值后修改当前 背景颜色。通过这个简单的演示足以说明 html5 中 postMessage 在进行跨域传输时的便捷性。


点击前:


点击后


(6)利用CORS进行跨域

CORS 名为跨域资源共享(Cross-Origin Resource Sharing),是通过控制网站 B 的相应头部字段来
浏览器中的跨域资源请求 http://rickgray.me/2015/09/03/solutions-to-cross-domain-...
第9页 共13页 2016/8/5 22:46
实现的。要实现CORS 必须对被请求的网站 B 做一定的设置,主要就是通过设置相应头中的 Access-Con trol-Allow-Origin 字段。Access-Control-Allow-Origin 响应字段说明了该资源或网站所允许被非同源站 点访问的站点列表,当 Access-Control-Allow-Origin 中包含网站 A 或者设置为 * 时,网站 A 即可对网 站 B 上的资源进行任意访问。 这里网站 B 使用 PHP 来设置 Access-Control-Allow-Origin 响应头字段。

<?php//header("Access-Control-Allow-Origin: *");  //先注释掉,看网站 A 是否能成功请求资源echo "Site B PHP resource!!";

网站 A 的页面 http://a.0xfa.club/cors/in.html 通过 XMLHttpRequest 来请求网站 B 的页面资源 http:/ /b.0xfa.club/cors/data.php:

<script>var xml = new XMLHttpRequest();xml.open('get', 'http://b.0xfa.club/cors/data.php', true);xml.onreadystatechange = function() {if (xml.readyState == 4 && xml.status==200) {console.log(xml.responseText);}}xml.send();</script>

尝试访问,发现在不设置网站 B 页面的响应头字段 Access-Control-Allow-Origin,同样会被同源策略所 限制。




0 0
原创粉丝点击