跨域问题浅析

什么是源(域)

在W3C的定义中,源是由协议主机(IP 地址或者域名)端口三者确定。如果两个 URL 的协议主机(IP 地址或者域名)端口都一样的话,那么这两个 URL 就是同源的。

同源策略

由于源与源之间是未知且默认的,所以非本源中的资源(即URL对应的资源)是不可控的。在早期的互联网,不同源的内容可以随意访问。因此有人就借此来攻击网站。如,在JavaScript脚本中添加恶意代码,然后让目标网站访问加载,从而实现攻击目标网站(即,XSS攻击)。此外还有CSRF(Cross-Site Request Forgery,跨站请求伪造)网络攻击的方式。由此可见,限制不同源之间的资源访问非常重要。

因此,出于安全的考虑,最早由Netscape公司于1995年在自家浏览器中引入同源策略,对不同源之间的资源交互进行了限制。后续各家浏览器厂商跟进引入。目前,所有的浏览器都在实行这个政策。

需要注意的是,并不是所有的不同源的资源交互操作都是禁止的。诸如,script 标签、img 标签等是允许跨域访问。

不同源也称为跨域。一般情况下,两者是同一个意思。

如何实现跨域资源共享

虽然同源策略保证了网站的安全,但很多时候又不得不访问不同源的资源。其实,在早期的时候,人们巧妙的借助script 标签、img 标签可以加载不同域资源的特性来实现跨域资源访问。即,JSONP (2005年)和 图片Ping。但这两种技术都存在一定的限制以及安全隐患,现在不是很推荐使用。后来,W3C在2014年1月16日正式发布CORS(Cross-Origin Resource Sharing,跨域资源共享)标准方案,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。使得跨域资源共享成为了一项安全可控可靠的技术。目前主流的浏览器已全部支持。

现在,最常用的跨域资源共享的技术是 CORSJSONP 更多情况下是 CORS 的一种替代方案(例如,不支持 CORS 的老浏览器);而 图片 Ping 技术基本很少见了。

跨域资源共享(CORS)

CORS(Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的 HTTP header组成,这些 HTTP 标头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。借助 CORS,web 服务器可以选择哪些跨域请求允许访问到它们的资源

CORS 工作过程

CORS 很简单,浏览器将 CORS 需要的相关信息通过请求头发送给服务器,服务器根据请求过来的信息判断是否允许访问,并把结果回传给浏览器。浏览器对接收的到信息进一步做处理,对于被拒绝的请求给出 CORS 错误。

  1. 首先浏览器依照 CORS 的规定,根据请求接口的复杂度区分为简单请求复杂请求
    1. 简单请求:将在请求头中附带Origin发送给 web 服务器
    2. 复杂请求:将根据请求的基本信息(包括OriginAccess-Control-Request-Method等)生成一个预检请求(Preflight request),向 web 服务器询问是否支持 CORS 。
  2. 当 web 服务器接收到请求时, 针对不同请求有如下处理:
    1. 简单请求:根据请求头中的Origin来决定是否拒绝响应。
      • 如果Origin指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 响应。浏览器发现,这个响应的头信息没有包含Access-Control-Allow-Origin字段就知道出错了,从而拦截响应数据并抛出 CORS 错误,被XMLHttpRequestonerror回调函数捕获;
      • 如果服务器认为这个请求可以接受,则在响应头中的Access-Control-Allow-Origin中会发接受的源信息。
    2. 预检请求:根据请求头中的OriginAccess-Control-Request-Method以及Access-Control-Request-Headers来判断是否允许这种类型的请求。
      • 如果服务器确认允许这一类的请求,则响应正常,并在响应头中携带Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers以及Access-Control-Max-Age等字段。然后,浏览器发送真实请求。这时发送的真实请求的处理逻辑和简单请求一致。
      • 如果服务器否认这一类的请求,同样会返回一个正常的 HTTP 响应。但是没有任何 CORS 相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此拦截响应数据触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。

关于浏览器拦截跨域请求的响应内容

当一个请求被浏览器识别为不允许的跨域请求时,浏览器会自动拦截请求的响应内容,阻止响应内容加载到渲染进程中。这也就是为什么在 Devtools 的 Network 中查看被阻止的跨域请求时,Response 是一片空白的原因。

其中,针对跨域标签(如:

你可能感兴趣的:(杂记,CORS,跨域,JSONP)