一. 什么是跨域?
出于安全考虑,浏览器限制页面脚木发起跨域请求,所以XMLHttpRequest和fetch API是遵循同源策略的。
例如,在http://domain-a.com 页面用XMLHttpRequest向http://domain-b.com 发起HTTP请求,这就是跨域。
补充:CSS、JS和图片等静态资源是不受同源策略限制的。
二. 为什么要限制跨域?
如果没有跨域限制,很容易发生下面这种情况:
-
首先,用户登陆银行网站https://www.bank.com, 返回用户认证信息并存在cookie。 -
然后,用户打开恶意网站http://www.hacker.com, 网页向https://www.bank.com 发起http请求。 -
最后,银行网站取出cookie, 验证用户身份无误并返回数据,造成了数据泄露。
这是一个典型的CSRF攻击。黑客在恶意网页向第三方网站发送伪造请求,造成数据泄露等危害。
但有些场景是存在跨域的。例如,在前后端分离的网站(前后端域名不同),前端网页怎么跨域请求后端服务呢?
三. 怎么实现跨域访问控制?
为了保证安全地进行跨域资源共享,就有了CORS机制,它允许服务器对跨域请求进行访问控制。
首先,把请求分为两类: simple request 和preflight request, 两者区别在于后者对服务器有副作用。
simple request:
在XMLHttprequest出现之前,就已经有<form>与服务器进行数据交互。
类似<form>的称为simple request, 必需满足以下两点:
HTTP Method为: GET、 POST、 HEAD。
HTTP Header 为:
- Accept、 Accept - Language、Content -Language。
- Content-Type: text/plain、multipart/ form-data、application/x-www-form-ur lencoded。
- Range:只允许简单的范围值,例如bytes=256-。
- 没有使用ReadableStream对象。
simple request使用origin和Access-Control-Allow-Origin来完成访问控制。
浏览器请求时带上origin (HTTP Header), 表示请求来源。
服务器响应时返回Access-Control-Allow-Origin (HTTP Header), 表示允许访问的源。
浏览器判断请求源origin是否在服务器允许访问的范围内Access-Control-Allow-origin,如果不在范围内,则返回失败。
preflight request :
如果请求对服务器有副作用,浏览器会先用OPTIONS方法发送一个preflight request,检查服务器是否允许跨域请服务器确认允许之后,浏览器才发起实际请求。避免跨域请求对服务器数据造成未预期的影响。
第一次OPTIONS请求:
对应响应:
-
Access-Control-Allow-Origin: 允许跨域的源。 -
Access-Control-Allow-Methods: 允许跨域的HTTP Method。 -
Access-Control-Allow- Headers: 允许跨域的HTTP Headers。
浏览器根据prefight request的请求和响应报文进行判断,如果服务器允许跨域,就发起真实请求,否则返回失败。
总结
一次跨域请求过程一般如下:
浏览器发起请求,origin和host 不同就会触发CORS机制,并自动带上origin。
服务器收到请求,根据实际的跨域访问控制需要,返回允许跨域的源。
浏览器收到响应,判断请求源不在服务器允许的范围内,则返回失败。
对服务器有副作用的跨域请求,浏览器会先发一个预检查请求,检查服务器是否允许跨城。
服务器确认允许之后,浏览器才发起实际请求。避免跨城请求对服务器数据造成未预期的影响。
|