Web跨域分析与解决

前言

本片章叙述一下跨域问题,原来业务上也有碰到过此类问题,都是搜索下答案先处理问题,只知如何解决但不知深原。

凡事多问个为什么嘛~这已经是两位前辈对我的深刻教诲了,深记于心。

多问:为什么?

 

一.跨域问题的由来

二.怎么就算跨域(同源的定义)

三.常见跨域解决方法

四.总结

 

一.跨域问题的由来

为什么会产生这样一个问题,摆在我们面前呢??

理解跨域,首先必须要了解同源策略。同源策略是浏览器上为安全性考虑实施的非常重要的安全策略。

为了防止某些文档或脚本加载别的域下的未知内容造成泄露隐私,破坏系统等安全行为

 

哦~说的很有道理,但脑子中没有什么体会认知吧?那咱们换个角度来说这个问题

假设没有同源, 互联网世界是什么样?

1.链接跳转导致的问题.

http://a.com , 放一个链接到 icbc.com, 然后 window.open来打开,window.open有个返回值句柄,

没有同源,a.com可以拥有对这个页面完全的控制权. 拦截表单,捕获数据,将账号密码上传到a.com等等.

 

2.ajax请求, 要啥就有啥.

你登录jd.com产生了登陆cookie;

然后打开a.com, a.com通过ajax 请求http://jd.com 的用户信息接口,

这时候因为你登陆jd.com,所以a.com发起访问jd.com自动带上了jd的合法cookie,绕过jd的登陆验证,

然后获取到你京东的订单list ,昵称, 所有私密信息返还给a.com.【是不是有点像CSRF?】

 

所以,为什么需要同源策略,显而易见,必须得限制跨域

(安全性和方便性是成反比的,同源策略提升了Web前端的安全性,但牺牲了Web拓展上的灵活性。所以,现代浏览器在安全性和可用性之间选择了一个平衡点。在遵循同源策略的基础上,选择性地为同源策略“开放了后门”。例如img script style等标签,都允许垮域引用资源,严格说这都是不符合同源要求的。)

 

二.怎么就算跨域(同源的定义)

1995年, Netscape 公司在浏览器中引入同源策略/SOP(Same origin policy)

同domain(或ip),同端口,同协议视为同一个域,一个域内的脚本仅仅具有本域内的权限,

可以理解为本域脚本只能读写本域内的资源,而无法访问其它域的资源。这种安全限制称为同源策略。

 

三.常见跨域解决方法

1.JSONP

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。

啥意思?正如前边提到的,ajax访问接口时受同源限制的,但是<script src="XXXX">是不受限制的,所以通过此方法避开同源限制。哈哈,本质是因为这样啊,钻了同源的漏网之鱼。【通过script的src来加载,这也解释了为什么jsonp只支持get传输】

为啥还要有callback参数?因为需要一个代理函数做中间人来处理数据,这个参数成了约定的函数名了。

这样jsonp的原理就很清楚了,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。

如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了.原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

 

 

2.CORS

CORS(跨域资源共享,Cross-Origin Resource Sharing)是通过客户端+服务端协作声明的方式来确保请求安全的

服务端会在HTTP请求头中增加一系列HTTP请求参数(例如Access-Control-Allow-Origin等),来限制哪些域的请求和哪些请求类型可以接受。

可以在代码里写,也可以写在服务器配置文件里。

 

先解释下有什么配置,不用全写,按需选取配置即可

Access-Control-Allow-Origin:指定授权访问的域

Access-Control-Allow-Methods:授权请求的方法(GET,POST,PUT,DELETE,OPTIONS等)

Access-Control-Allow-Credentials 首部字段用于预检请求的响应,表明服务器是否允许,credentials标志设置为true的请求。

Access-Control-Max-Age:<delta-seconds> 首部字段指明了预检请求的响应的有效时间。delta-seconds 表示该响应在多少秒内有效。

Access-Control-Allow-Headers 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。

 

实现ajax跨域访问

配置可以在代码里,

也可以写在服务器配置文件(apache,nginx)里。

1)php代码
header('Access-Control-Allow-Origin:*');  // 指定允许其他域名访问  
header('Access-Control-Allow-Methods:POST');  // 响应类型  
header('Access-Control-Allow-Credentials:true');  //允许客户端传输cookie

2) Nginx
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Credentials' "true";

3) Apache
Header set Access-Control-Allow-Origin www.a.com
(打开Credentials与Methods方式暂时报错,待尝试)

 

/**
     * yii2 行为方法,自动执行打开跨域@inheritdoc
     */
    public function behaviors()
    {

        return [
            
            'corsFilter' => [
                'class' => \yii\filters\Cors::className(),
                'cors' => [
                    'Origin' => ['http://a.com','http://b.com'],//多域名设置
                    'Access-Control-Allow-Credentials' => true,
                ]
            ],
        ];
    }
    
<!-- 前台跨域代码格式 -->
 $.ajax({
     type: 'POST',
     url: 'http://www.b.com' ,
     data: {id:1} ,
     dataType: 'json',
     xhrFields: {withCredentials: 'true'},
     success:function(){alert(121);}
});

 

效果演示 :以修改apache,nginx配置文件的方法为例子

图1.前台跨域代码

 

图2.触发跨域后的提示

 

图3.apache配置打开跨域

 

图4.nginx打开跨域限制

图5.再次调用跨域成功

 

 

 

c.iframe

本质www.a调用不了www.b下的东西,但是a可以iframe打开一个b域名下的第三个页面c,c与b是同域名让c来调用b

所以ifame的本质就是,把a要调用b的代码逻辑写到c里边,然后把c召唤出来即可,剩下的c来做也不涉及跨域.

这里文章介绍的很好:http://blog.csdn.net/fdipzone/article/details/17619673/

 

4、其它一些方式

WebSocket、服务器代理、flash socket。这里接不详细叙述说了。

 

四.总结:

这么一看,跨域限制还是很有必要的,安全。

但是为了方便,同源限制也开放了几个可以跨域访问的标签<img><script><style>等

但是就是因为这个小缺口的开放不也是产生CSRF的可乘之机嘛

所以说,安全与便捷总是相对力点,就像原来听说支付宝想推出一款扫物品就能付款的产品,出门不用带钱包了,带上这个设定的物体就行了,方便是方便了,但是多危险吗丢了别人就随便拿来支付了吗。(不过后来也没见阿里推出该产品哈哈)

 

五。注意点

1.关于Access-Control-Allow-Origin设置多域名问题

总不能给服务器设置*吧太危险了,但是又想设置多域名,不能简单的加逗号

比如:add_header 'Access-Control-Allow-Origin' 'www.a.com,www.b.com'; 是错误

因该怎么做呢?加入逻辑代码,把它变量化。

$origin = isset($_SERVER['HTTP_ORIGIN'])? $_SERVER['HTTP_ORIGIN'] : ''; 
$allow_origin = array( 'http://client1.runoob.com', 'http://client2.runoob.com' );
if(in_array($origin, $allow_origin)){header('Access-Control-Allow-Origin:'.$origin); }
if ($http_origin ~ <允许的域(正则匹配)>) { add_header 'Access-Control-Allow-Origin'"$http_origin";
if ($request_method = "OPTIONS") {...}
}

2.关于Credentials设置问题

我们从上文知道,Credentials是开启传输cookie的一个开关

但是注意:

1).首先:服务器Access-Control-Allow-Origin【不能设置成*】 得设置成对应域名,否则无效!!!

2).其次,只在服务端设置开启Access-Control-Allow-Credentials服务器打开不行,

还得客户端打开withCredentials=true,否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

 

3.配置完成以后还是报错, that is not equal to the supplied origin,去看看你allow的域名是否携带了" / ",斜杠,有斜杠会报错

XMLHttpRequest cannot load  abc.com/B. The 'Access-Control-Allow-Origin' header has a value 'http://A.abc.org/' that is not equal to the supplied origin. Origin 'http://A.abc.org' is therefore not allowed access.

4.cors预检请求问题

若http请求不是get,post,head,或者携带header头过多,浏览器会先预检请求(option(经测试确实存在两次请求)

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

 

参考文章:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

iframe与主框架跨域相互访问方法http://blog.csdn.net/fdipzone/article/details/17619673/

js中几种实用的跨域方法原理详解http://www.cnblogs.com/2050/p/3191744.html

前端跨域请求如何实现https://ask.zkbhj.com/?/question/96

 

本文地址:http://blog.csdn.net/ty_hf/article/details/76408790

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值