浏览器同源策略与跨域实现、OPTIONS请求

含义

1995年,同源政策 由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个策略。

最初,它的含义是指,A网站设置的 Cookie,B网站不能打开,除非这两个网站 同源

所谓 同源 指的是 三个相同

  • 协议相同
  • 域名相同
  • 端口相同

举例来说,http://www.example.com/dir/page.html 这个网址,

  • 协议是 http://
  • 域名是 www.example.com
  • 端口是 80(默认端口可以省略)

它的同源网址如下:

  • http://www.example.com/dir2/other.html:同源
  • http://example.com/dir/other.html:不同源(域名不同)
  • http://v2.www.example.com/dir/other.html:不同源(域名不同)
  • http://www.example.com:81/dir/other.html:不同源(端口不同)

目的

同源政策的目的,是为了 保证用户信息的安全防止恶意的网站窃取数据

设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?

很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。

由此可见,”同源政策”是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。

限制范围

随着互联网的发展,同源政策 越来越严格。目前,如果非同源,有三种行为受到限制:

  1. AJAX 请求不能发送

  2. Cookie、LocalStorage 和 IndexDB 无法读取。

  3. DOM 无法获得。

虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。

跨域-让AJAX不受限制

同源政策规定,AJAX请求只能发给同源的网址,否则就报错。

有三种方法规避这个限制:

  • CORS
    CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法,允许任何类型的请求。

  • nginx反向代理

  • JSONP

CORS

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

CORS 需要 浏览器服务器 同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。

整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。

两种请求

浏览器将CORS请求分成两类:简单请求(simple request)非简单请求(not-so-simple request)

简单请求

同时满足以下条件,就属于简单请求:

请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain

Content-Type只能取以下几个值:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

执行流程

  1. 在请求中需要附加一个额外的 Origin 头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。例如:Origin: http://www.laixiangran.cn

  2. 如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin 头部中回发相同的源信息(如果是公共资源,可以回发 * )。例如:Access-Control-Allow-Origin:http://www.laixiangran.cn

  3. 没有这个头部或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。
    注意:请求和响应都不包含 cookie

浏览器向服务器发送 cookie 信息,需要进行下面操作:

前端:

  • ajax 请求需要设置 xhr 的属性 withCredentialstrue

后端:

  • 服务器需要允许cookie,设置响应头 Access-Control-Allow-Credentials: true

  • 设置响应头 Access-Control-Allow-Origin* 即可,表示后端服务器允许 任意前端服务器 跨域不安全
    更安全的做法是:指定 前端服务器域名,如:http://localhost:9528(末尾不能有符号 /

  • 设置响应头 Access-Control-Allow-Headers* 即可

非简单请求

不同时满足上面条件的,就是 非简单请求

比如:

  • 请求方法是PUT或DELETE
  • Content-Type字段的类型是 application/json,即:发送json数据

执行流程

  1. 浏览器在发送真正的请求之前,会先发送一个 Preflight 请求给服务器,这种请求使用 OPTIONS 方法,发送下列头部:

    Origin:与简单的请求相同。
    Access-Control-Request-Method: 请求自身使用的方法。
    Access-Control-Request-Headers: (可选)自定义的头部信息,多个头部以逗号分隔。
    

    例如:

    Origin: http://www.laixiangran.cn
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: NCZ
    
  2. 发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通:

    Access-Control-Allow-Origin:与简单的请求相同。
    Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔。
    Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔。
    Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)。
    

    例如:

    Access-Control-Allow-Origin: http://www.laixiangran.cn
    Access-Control-Allow-Methods: GET, POST
    Access-Control-Allow-Headers: NCZ
    Access-Control-Max-Age: 1728000
    

一旦服务器通过 Preflight 请求允许该请求之后,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样了。

浏览器向服务器发送 cookie 信息,需要进行下面操作:

前端:

  • ajax 请求需要设置 xhr 的属性 withCredentialstrue

后端:

  • 服务器需要允许cookie,设置响应头 Access-Control-Allow-Credentials: true

  • 返回的响应头 Access-Control-Allow-Origin,值不能是 *,应该是 与请求网页一致的域名,如:http://localhost:9528(末尾不能有符号 /

  • 返回的响应头 Access-Control-Allow-Headers,值不能是 *,如:access-control-allow-origin, authority, content-type, version-info, X-Requested-With

跨域优缺点

优点

CORS 通信与同源的 AJAX 通信没有差别,代码完全一样,容易维护。
支持所有类型的 HTTP 请求。

缺点

存在兼容性问题,特别是 IE10 以下的浏览器。
第一次发送非简单请求时会多一次请求。

参考:
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://www.cnblogs.com/laixiangran/p/9064769.html


原文出处:https://www.malaoshi.top/show_1IXBXRNJyf2.html