新编第一章

前言

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

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

多问:为什么?

一.跨域问题的由来

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

三.常见跨域解决方法

四.总结

一.跨域问题的由来

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

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

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

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

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

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访问接口时受同源限制的,但是

为啥还要有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 表示该响应在多少秒内有效。

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

实现ajax跨域访问

配置可以在代码里,

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

[plain] view plain copy

  1. 1)php代码

  2. header('Access-Control-Allow-Origin:*'); // 指定允许其他域名访问

  3. header('Access-Control-Allow-Methods:POST'); // 响应类型

  4. header('Access-Control-Allow-Credentials:true'); //允许客户端传输cookie

  5. 2) Nginx

  6. add_header 'Access-Control-Allow-Origin' '*';

  7. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

  8. add_header 'Access-Control-Allow-Credentials' "true";

  9. 3) Apache

  10. Header set Access-Control-Allow-Origin www.a.com

  11. (打开Credentials与Methods方式暂时报错,待尝试)

[php] view plain copy

  1. /**

    • yii2 行为方法,自动执行打开跨域@inheritdoc
  2. */

  3. public behaviors()

  4. {

  5. return [

  6. 'corsFilter' => [

  7. 'class' => \yii\filters\Cors::className(),

  8. 'cors' => [

  9. 'Origin''http://a.com''http://b.com'],//多域名设置

  10. 'Access-Control-Allow-Credentials' => true,

  11. ]

  12. ],

  13. ];

  14. }

[javascript] view plain copy

  1. $.ajax({
  2. type: 'POST',
  3. url: 'http://www.b.com' ,
  4. data: {id:1} ,
  5. dataType: 'json',
  6. xhrFields: {withCredentials: 'true'},
  7. success:function(){alert(121);}
  8. });

效果演示 :以修改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来做也不涉及跨域.

这里文章介绍的很好:iframe与主框架跨域相互访问方法_傲雪星枫的博客-CSDN博客_iframe跨域

4、其它一些方式

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

四.总结:

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

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

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

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

五。注意点

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

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

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

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

[plain] view plain copy

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

2.关于Credentials设置问题

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

但是注意:

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

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

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

3.cors预检请求问题

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

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

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
1
粉丝
0
喜欢
1
收藏
0
排名:3296
访问:85
私信
所有博文
社区赞助商