web开发中的浏览器跨域整理

作者: 进击的诺基亚 | 来源:发表于2016-08-24 17:15 被阅读577次

HTTP访问控制(CORS)

同源策略
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
为什么不能跨域访问
跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是CSRF跨站攻击原理,无论是否跨域,请求是发送到了后端服务器,注意:有些浏览器不允许从HTTPS的域跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。所以只有服务器允许跨域,并且在相应包的头信息里面指明允许跨域,那么跨域请求的响应数据就不会被浏览器拦截丢弃了。

什么是跨域

URL1 URL2 是否跨域 原因
http://kangbiao.org/index https://kangbiao.org/index 协议不同
http://kangbiao.org/index http://kangbiao.org:8080/index 端口号不同
http://kangbiao.org/index http://baidu.org/index 主机不同
http://kangbiao.org/index http://t1.kangbiao.org/index 主机不同

通过上面的比较可以归纳出,跨域是指协议、主机地址、端口号这三个条件只要有一个不同则认为是跨域。

六种跨域方式

通过浏览器对象解决

document.domain(适用于子域跨域)
在同源策略中有一个例外,脚本可以设置 document.domain
的值为当前域的一个后缀,如果这样做的话,短的域将作为后续同源检测的依据。例如,假设在 http://t1.kangbiao.org/index 中的一个js脚本执行了下列语句:
document.domain = "kanbgiao.org";
这条语句执行之后,页面将会成功地通过对 http://company.com/index
的同源检测。但是不能通过设置 document.domain = "notkangbiao.org";完成对其他域的访问,该方法只适用于子域和父域之间的跨域解决。

使用document.domain来让子域安全地访问其父域,需要同时将子域和父域的document.domain设置为相同的值,没有这么做的话会导致授权错误。

window.name
这种方案实用性不高,实现也挺麻烦,也不够灵活,所以我就不详细写了,有兴趣可以参考这篇文章

客户端和服务端配合实现jsonp

jsonp其实就是动态创建js脚本。虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的函数,因此可以将script的src属性设为需要跨域的接口地址,但是需要服务器将数据组装成js变量定义或者函数传回来,举例如下:
比如kangbiao.org/index 需要调用t1.kangbiao.org/getServerInfo接口获取服务器信息,原来该接口的返回是:

{
  "ip":"192.168.1.1",
  "cpu":"Intel i5",
  "network":"100M"
}

现在为了配合jsonp的话返回格式应该如下:

  var response={
  "ip":"192.168.1.1",
  "cpu":"Intel i5",
  "network":"100M"
};

所以jsonp就是在返回数据中定义一个js变量或者函数来实现动态创建js脚本,这样做的缺点也显而易见,会出现变量污染或者函数重名(可以通过生命一个服务器专用的函数对象解决),而且服务器和前端脚本变量绑定太强,不是很灵活。

采用HTML5中的postMessage解决

postMessage可以实现窗口和窗口,页面和iframe,页面和窗口间的跨域通信。
postMessage需要源网站和跨域网站同时实现两个接口postMessage(发送数据)和addEventListener(监听事件,接受数据)

otherWindow.postMessage(message, targetOrigin);

otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames

message
将要发送到其他 window的数据。

targetOrigin
通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的orign属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。

target.addEventListener(type, listener[, useCapture]);

type
表示所监听事件类型的一个字符串。

listener
当指定的事件类型发生时被通知到的一个对象。该参数必是实现
EventListener
接口的一个对象或函数。

useCapture
可选
如果值为true, useCapture表示用户希望发起捕获。 在发起捕获之后, 只要Dom子树下发生了该事件类型,都会先被派发到该注册监听器,然后再被派发到Dom子树中的注册监听器中。并且向上冒泡的事件不会触发那些发起捕获的事件监听器。进一步的解释可以查看 DOM Level 3 Events 文档。 请注意该参数并不是在所有的浏览器版本中都是可选的。如果没有指定, useCapture默认为false 。

两个函数的定义如上,addEventListener不是html5中特有的,postMessage是html新增实现跨域通信的。
如果需要跨域交换数据,则需要两边都需要同时实现这两个接口,才能交换数据,不然只能单方向的接收或者发送数据。一般的实现是在addEventListener的回掉函数中通过event.data获取到传过来的数据后,再次调用postMessage将处理后的数据返回给消息来源对象。这样实现好处就是完全不需要后端的参与。但是有一定的安全风险,配合xss可以导致用户凭证信息被盗取。
具体的代码示例参考postMessage实示例

服务器响应头控制(CORS 跨域资源共享)

这种方法是我认为最好的方法,由服务器决定是否允许跨域,如果允许,服务器在响应头中添加相应的字段告诉浏览器此次跨域合法,则浏览器不会将请求包丢弃(文章开头说了跨域其实是浏览器的一种行为),从而完成跨域。
这种方法的详细操作我就不多说了,参考廖雪峰的这篇文章
主要叙述下服务端怎么设置响应头
在PHP中可以中国header()函数设置允许跨域字段
在java中可以通过设置reponse.setHeader()函数来设置,spring4.2及以上版本提供了@CrossOrigin注解来方便实现跨域。

服务器代理

服务器代理就是将需要跨域访问的地址通过服务器访问(服务器此时作为客户端,不会受同源策略限制),然后由服务器返回结果。
例如kangbiao.org/index 页面需要访问api.weibo.com/getNews 来获取最新新闻,我们可以通过在kangbiao.org的服务器上面多增加一个接口 kangbiao.org/api?url=api.weibo.com/getNews ,然后再服务器内部,该接口所做的事情就是向api.weibo.com/getNews 发起请求即可,然后将结果返回。
这样做的好处是实现十分简单,而且可以访问任何跨域站点,缺点就是需要新增维护一个接口,而且如果服务器是通过代理网关,只能内网通信的话也很麻烦。

反向代理

反向代理也是在服务器实现的,主要是通过正则匹配url,匹配成功后重写到目标地址即可,这种方法可以实现所有网站的跨域,不需要服务器提供跨域支持,个人认为比较方便,甚至可以配置kangbiao.org/proxy/weibo/实现将api.weibo.com域的接口整合到我们自己的网站下面来,并且程序不需要做任何改动,改下nginx的配置文件即可。具体的实现方案很多,google或者百度nginx反向代理实现跨域即可。

参考文章

相关文章

  • 实现跨域请求的八种方式

    前端开发中我们经常会遇到跨域请求的情况,处理跨域请求方式很多,特整理如下: 浏览器的同源策略 提到跨域不能不先说一...

  • 就是要跨域

    由于CORS(跨域)本身是具有安全隐患的,因此浏览器默认是禁止的。但跨域却在web开发中具有很重要的作用,也是前端...

  • web开发中的浏览器跨域整理

    HTTP访问控制(CORS) 同源策略同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。设想这样一...

  • 跨域的几种解决方案

    跨域是web开发中经常会遇到的情况,只出现在浏览器端。本文列举了一些常见的跨域情况,和解决方案。 什么是跨域,为什...

  • 前端跨域的整理

    跨域资源共享 CORS 对于web开发来讲,由于浏览器的同源策略,我们需要经常使用一些hack的方法去跨域获取资源...

  • ASP.NET Core笔试题 说说脚本在请求Web CoreA

    ### 说说脚本在请求Web CoreApi的时候,为什么会发生跨域问题? 跨域问题:本质是浏览器的行为,浏览器有...

  • 129-跨域(一)ajax跨域访问、解决跨域后session失效

    1. ajax跨域 在Web编程中我们经常会遇到跨域的问题。默认情况下,浏览器是不允许跨域访问的。所以说,在这里就...

  • 一个iOS程序员眼中的跨域问题

    摘要: 跨域问题是web开发领域一个常见的问题,相信每个web开发者都遇到“跨域”的问题最近公司的iOS开发任务比...

  • 跨域

    什么是跨域 跨域指的是浏览器源文档访问另一个源文档。具体可以查看web同源策略 为什么要有跨域 跨域是出于浏览区安...

  • Chrome浏览器的跨域问题

    解决Chrome浏览器的跨域问题 对于前端来说,本地开发很经常会遇到跨域问题,最简单的方法就是将浏览器设置成可跨域...

网友评论

本文标题:web开发中的浏览器跨域整理

本文链接:https://www.haomeiwen.com/subject/jfynsttx.html