浏览器同源策略,及跨域解决方案

一、Origin(源)

源由下面三个部分组成:

  1. 域名
  2. 端口
  3. 协议

两个 URL ,只有这三个都相同的情况下,才可以称为同源。

下来就以 "http://www.example.com/page.html" 这个链接来比较说明:

对比URL 结果 原因
http://m.example.com/page.html 不同源 域名不同
https://www.example.com/page.html 不同源 协议不同
http://www.example.com:8080/page.html 不同源 端口不同
http://www.example.com/page3.html 同源 同域名,同端口,同协议

二、同源策略

浏览器的同源策略是一种安全功能,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

三、哪些会受到同源策略限制

对于浏览器来说,除了DOM、Cookie、XMLHttpRequest 会受到同源策略的限制外,浏览器加载的一些第三方插件也有各自的同源策略。最常见的一些插件如 Flash ,有自己的控制策略。

所以,想要体验下,同源策略限制,你就可以写一个ajax 请求,比如127.0.0.1:80 要请求127.0.0.1:8080 的 a.js ;

127.0.0.1:80 里的index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>另一个页面</h1>
</body>
        <script>
            var xhr = new XMLHttpRequest();
            xhr.open(‘get‘,‘http://127.0.0.1:8080/index.js‘);
            xhr.send(null);

            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                    alert(xhr.responseText);
                }
            }
        </script>
</html>

然后就会报错了,出现了同源策略限制了。

四、什么是跨域呢

说的跨域,其实呢就是跨源。而跨域是一个统称,通过上面的我们知道了,因为同源策略,不同源之间,不能进行交互。那么跨域就是解决不同源之间发起请求、请求数据、发送数据、通信等交互问题解决方法的统称。

在浏览器中,<script><img><iframe><link><video> 等标签都可以跨域加载资源,而不受同源策略的限制,通过 src 属性加载的资源,浏览器都会发起一个 GET 请求,但是浏览器限制了 JavaScript 的权限,使用js不能读、写加载的内容。

这句话什么意思呢,其实就是,你可以通过这几个标签来跨域加载资源,但是,发起的GET请求 返回的数据,通过 js 获取不到。

注意:通过 <script> 标签获取 js 文件里的全局属性,方法等,可以通过 js 读取到。是因为这些都是挂载在 window对象上的,看下面:

127.0.0.1 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
    <script type="text/javascript" src="http://127.0.0.1:8080/index.js"></script>
    <script type="text/javascript">
        window.onload = function(){
            say();
        }
    </script>
</body>
</html>

127.0.0.1:8080 index.js

function say(){
    var app = document.getElementById(‘app‘);
    app.innerHTML = "我是被挂载到window对象上的方法,所以可以获取到我!";
}

五、jsonp跨域

到底什么是jsonp 跨域呢?其实,jsonp 跟 json 两者没有什么关系,也没有什么相似的地方,大家都知道json 是一种数据格式,而jsonp 之所以被称为jsonp,我认为跟它发出请求后,一般得到的,都是json格式数据有关吧。

上面说过了,<script><img><iframe><link><video>这些标签都可以发起跨域请求,其中的 <script> 标签都熟悉吧,经常用来加载 js 文件。jsonp就是利用了这个标签。

不知道大家有没有疑问啊,既然这些标签都能发起跨域请求,那么为啥只用 <script>标签可以请求到数据呢?其实呢,关键就在于,<script>再请求得到数据后,遇到js代码,就会解析执行。理解这个也不难,你在js文件里写的代码,肯定是要被执行的。

比如127.0.0.1 里的index.html 页面加载了一个 <script src="index.js"></script>

function say(){
    console.log("666");
}
say();

当打开127.0.0.1/index.html页面时,<script>标签发起了一个对index.js 的 GET 请求,得到数据后,js引擎开始解析执行,然后say方法就被执行了,这时,控制台就会输出 "666";

那么jsonp就是利用了这点了。先来写一个jsonp实例吧。

127.0.0.1 jsonp.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>JSONP</h1>
</body>
    <script >
        function say(data){
            alert(data);
        }
    </script>
    <script src="http://127.0.0.1:8080/index.php?callback=say"></script>
</html>

然后是 127.0.0.1:8080 index.php文件:

<?php

$data = array(
                ‘name‘ => ‘zdx‘,
                ‘sex‘ => ‘man‘,
                ‘age‘ => 18

             );
$callback = $_GET[‘callback‘];
echo $callback . ‘(‘ . json_encode($data) . ‘)‘;
?>

当访问jsonp.html时,其中的<script>发起一个请求,并发送了一个名为callback参数,值为字符串"say"。然后index.php 把传进来的 say 和要发送的 data 进行字符串拼接,json_encode 函数就是把 数据转成json 格式的。然后这个请求就返回了:say({"name":"zdx","sex":"man","age":18});然后 <script>得到这个数据后,就会解析执行 say 函数了。

所以明白了吧,jsonp 是需要后端 支持的,需要配套使用,然后关于jsonp 是存在安全风险的,传过来的数据直接执行,那么只要改掉同名的函数,那么想怎么操作数据都可以了。还可以修改参数值,对传到服务器的数据进行修改,从而攻击服务器。

注意:此方法只能发起GET请求,通过jsonp发送的请求,会随带 cookie 一起发送。

六、CORS跨域(跨域资源共享)

CORS(Cross-Origin Resource Sharing,跨源资源共享)定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

注意:此方法IE8以下完全不支持,IE8-10部分支持。

这需要服务器 和前端配合, 或者 后端 和 前端配合。

可以看看阮老师的:跨域资源共享 CORS 详解

这里以 php 为例,只需在需要被请求的 php 文件里加上一个响应头部 header(‘Access-Control-Allow-Origin:http://127.0.0.1‘),后面的域名就是允许请求的域名。这里就是表示允许来自http://127.0.0.1所有的请求。

127.0.0.1:8080 index.php

<?php

    header(‘Access-Control-Allow-Origin:http://127.0.0.1‘);

    echo "我是CORS跨域过来的!";
?>

然后就是前端了。IE10及以上、Firefox 3.5+、Safari 4+、Chrome、iOS版 Safari和 Android平台中的 WebKit都通过 XMLHttpRequest 对象实现了对 CORS 的原生支持。

127.0.0.1:80 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>另一个页面</h1>
</body>
    <script>
        var xhr = new XMLHttpRequest();
        xhr.open(‘get‘,‘http://127.0.0.1:8080/index.php‘);
        xhr.send(null);

        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
                alert(xhr.responseText);
            }
        }
    </script>
</html>

而IE8 - IE9是通过XDR对象实现 CORS 的。

基于XDR的 index.html 代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>XDR对象实现CORS</title>
</head>
<body>
    <h1>XDR对象实现CORS</h1>
    <script>
        var xdr = new XDomainRequest();
        xdr.onload = function(){
            console.log(xdr.responseText);
        };
        xdr.open("get","http:127.0.0.1:8080/index.php");
        xdr.send(null);
    </script>
</body>
</html>

注意:CORS可以发起 GET、POST请求,但是发送的请求,默认不会随带 cookie 一起发送, 也不会接受后端发过来的 cookie;

要想随带cookie 一起发送。

需要在127.0.0.1:8080 index.php添加 header(‘Access-Control-Allow-Credentials:true‘);头部,然后在127.0.0.1:80 index.htmlvar xhr = new XMLHttpRequest();后面添加xhr.withCredentials = true;

七、document.domain 降域

同源策略认为域和子域属于不同的域,如:

child1.a.com 与 a.com,

child1.a.com 与 child2.a.com,

xxx.child1.a.com 与 child1.a.com

两两不同源,可以通过设置 document.domain=‘a.com‘,浏览器就会认为它们都是同一个源。想要实现以上任意两个页面之间的通信,两个页面必须都设置documen.damain=‘a.com‘。

此方式的特点:

  1. 只能在父域名与子域名之间使用,且将 xxx.child1.a.com域名设置为a.com后,不能再设置成child1.a.com。
  2. 存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞。
  3. 这种方法只适用于 Cookie 和 iframe 窗口。

下面来模拟一下,在a.com 与 child1.a.com 之间通信。如果要在本机测试,请自行更改host 等,访问的都是本机80端口,这里就不在累述了。

a.com index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>主页面</h1>
    <script>
        document.domain = ‘a.com‘;
    </script>
    <iframe src="http://child1.a.com/index1.html" frameborder="0"></iframe>
</body>
</html>

child1.a.com index.php

<?php
    echo "我是document.domain 降域过来的!";
?>

child1.a.com index1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>child</h1>
    <script>
        document.domain = ‘a.com‘;

        var xhr = new XMLHttpRequest();
        xhr.open(‘get‘,‘http://child1.a.com/index.php‘);
        xhr.send(null);

        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4 && xhr.status >= 200 && xhr.status <= 300 || xhr.status == 304){
                alert(xhr.responseText);
            }
        }
    </script>
</body>
</html>

注意:此方法可以发起 GET、POST 请求,发起的请求不会随带 cookie 一起发送,也不能接受后端发过来的 cookie

八、HTML5的postMessage方法

这是html5 新加的方法。

这个方法允许一个页面的脚本发送数据到另一个页面的脚本中,不管脚本是否跨域。在一个window对象上调用postMessage()会异步的触发window上的onmessage事件,然后触发定义好的事件处理方法。一个页面上的脚本仍然不能直接访问另外一个页面上的方法或者变量,但是他们可以安全的通过消息传递技术交流。

比如说父页面为127.0.0.1:80 的页面,传送数据给 127.0.0.1:8080 的子页面:

127.0.0.1:80 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>父页面</h1>
    <iframe id="iframe" src="http://127.0.0.1:8080/ty/index6.html" frameborder="0"></iframe>
</body>
    <script>
        window.onload = function(){
            var wd = document.getElementById(‘iframe‘).contentWindow;
            wd.postMessage(‘我是通过postMessage方法过来的!‘,‘http://127.0.0.1:8080‘);
        }
    </script>
</html>

127.0.0.1:8080 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>子页面</h1>
</body>
    <script>
        window.addEventListener("message", receiveMessage, false);

        function receiveMessage(event)
        {
          alert(event.data)

        }
    </script>
</html>

然后访问:127.0.0.1:80/index.html,就得到想要的结果了,这方法通常用来进行两个窗口通信。

九、HTML5的WebSocket

现代浏览器允许脚本直连一个WebSocket地址而不管同源策略。然而,使用WebSocket URI的时候,在请求中插入Origin头就可以标识脚本请求的源。为了确保跨站安全,WebSocket服务器必须根据允许接受请求的白名单中的源列表比较头数据。

这个因为需要后端的支持,而且比较复杂,这里就不举例子了,感兴趣的可以去查阅资料。

这里贴一个阮老师的websocket教程吧:WebSocket 教程

十、window.name

window对象有一个name属性,该属性有一个特征:即在一个窗口的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久的存在于一个窗口载入的所有页面中的,并不会因为新的页面的载入而被重置。

因此,就可以利用此特性,进行跨域通信。

127.0.0.1:80 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body  id="data">
    <h1>window.name</h1>
</body>
<script type="text/javascript">
    window.name = "我是document.name过来的数据。"
    location.href = "http://127.0.0.1:8080/ty/index8.html";
</script>
</html>

127.0.0.1:8080 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        alert(window.name)
    </script>
</body>
</html>

这时,访问127.0.0.1:80/index.html,跳转到的127.0.0.1:8080/index.html就能接受传过来的数据了。

十一、location.hash

原理是利用location.hash来进行传值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash

127.0.0.1:80 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body  id="data">
    <h1>window.name</h1>
</body>
<script type="text/javascript">
    location.hash = "我是document.name过来的数据。"
    location.href = "http://127.0.0.1:8080/index.html" + location.hash;
</script>
</html>

127.0.0.1:8080 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        alert(decodeURIComponent(location.hash.slice(1)));
    </script>
</body>
</html>

这时,访问127.0.0.1:80/index.html,跳转到的127.0.0.1:8080/index.html就能接受传过来的数据了。

十二、proxy 跨域

这个完全是后端的实现,我就不说了,我也搞不懂,也没意义。哈哈。

这里说的还是皮毛,这些跨域方案只是工具,怎么利用,就看你了。

原文地址:https://www.cnblogs.com/zhoudaxiaa/p/9705749.html

时间: 2024-10-10 01:45:19

浏览器同源策略,及跨域解决方案的相关文章

浏览器的同源策略及跨域解决方案

同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: URL 结果 原因 http://a.xyz.com/dir2/other.html 成功   http://a.xyz.com/dir/inner/another.html 成功   https://a.xyz.com/secure.html 失败 不同协议 ( https和http ) h

同源策略和跨域解决方案

同源策略 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: URL 结果 原因 http://a.xyz.com/dir2/other.html 成功   http://a.xyz.com/dir/inner/another.html 成功   https://a.xyz.com/secure.html 失败 不同协议 ( https和http ) h

同源策略、跨域解决方案

一.定义 1.什么是源? 源(origin)就是协议.域名和端口号.以上url中的源就是:http://www.company.com:80若地址里面的协议.域名和端口号均相同则属于同源.以下是相对于 http://www.a.com/test/index.html 的同源检测? http://www.a.com/dir/page.html ----成功? http://www.child.a.com/test/index.html ----失败,域名不同? https://www.a.com/

浏览器同源策略与跨域出现原因

什么是同源策略? 同源策略(Same origin policy)是一种约定,它是浏览器最核心的也是最基本的安全功能,web也是构建在同源策略基础上,浏览器只是针对同源策略的一种实现. 它是由Netscape提出的一个著名的安全策略,目前支持JavaScript的浏览器都会使用找个策略. 什么是同源? 同源:域名/端口/协议相同 同源分为两种情况:1.dom的同源策略:禁止对不同页面的dom进行操作 2.XMLHttpRequest同源:禁止使用XHR对象向不同源的ip发起http请求 为什么会

同源策略防跨域解决方案

跨域 由于同源策略导致的不同源网站间页面脚本无法互相访问. 同源策略 出于安全性考虑,一个网站的脚本不能访问另一个网站的请求.除非它们的协议号,域名,端口号相同. 防跨域 同源策略条件过于严苛,很多网站都有子域名,这样就造成了互相通信不便的问题. 解决方案 一.document.domain document.domain只能实现一级域名相同的防跨域. 如:www.sojson.com 下指到sojson.com 是可以的. icp.sojson.com 下指到 sojson.com 是可以的.

Django - - 同源策略和跨域解决方案

目录 同源策略 一个源的定义 同源策略是什么 举个例子 jQuery中getJSON方法 JSONP应用 1, 同源策略 1.1 一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源. 举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: URL 结果 原因 http://a.xyz.com/dir2/other.html 成功 http://a.xyz.com/dir/inner/another.html 成

浏览器的同源策略和跨域访问

1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略.    何谓同源:        URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源.    同源策略:        浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性.        从一个域上加载的脚本不允许访问另外一个域的文档属性. 举个例子:      

【转】同源策略和跨域请求解决方案

一.一个源的定义 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源.举个例子: 下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: URL 结果 原因 http://a.xyz.com/dir2/other.html 成功 协议,端口(如果有指定)和域名都相同 http://a.xyz.com/dir/inner/another.html 成功 协议,端口(如果有指定)和域名都相同 https://a.xyz.com/secure

解说同源策略和跨域访问

尽管浏览器的安全措施多种多样,但是要想黑掉一个Web应用,只要在浏览器的多种安全措施中找到某种措施的一个漏洞或者绕过一种安全措施的方法即可.浏览器的各种保安措施之间都试图保持相互独立,但是攻击者只要能在出错的地方注入少许JavaScript,所有安全控制几乎全部瓦解--最后还起作用的就是最弱的安全防线:同源策略.同源策略管辖着所有保安措施,然而,由于浏览器及其插件,诸如Acrobat Reader.Flash 和Outlook Express漏洞频出,致使同源策略也频频告破. 既然web应用的最

11. cookie_session_原生ajax_readyState的值_同源策略_跨域_jsonp的使用

1. cookie 浏览器存储技术.(服务器将少量数据交于浏览器存储管理) 作用: 存储数据, 解决 http 协议无状态问题 工作流程: 浏览器发送请求给服务器,请求登录 服务器返回响应给浏览器,此时携带了cookie(其中包含着当前用户的唯一标识) 浏览器接受到响应中cookie,得保存下来 浏览器下一次发送请求时,会自动携带上cookie, 服务器接受到请求,解析cookie,从而判断是哪个用户发送的请求(解决http协议无状态问题) 服务器端的使用: 设置cookie        re