Published on

浏览器跨域

Authors

这篇我们来关注浏览器跨域

浏览器跨域是什么?

跨域请求拦截是浏览器为了请求安全引入的基于同源策略实现的安全特性,当用户在一个页面上(baidu.com)尝试请求另一个来源的数据(api.baidu.com)时,如果协议、域名、端口号任意不同,守卫就会拦截请求

如何触发浏览器跨域?

当发出请求的协议,域名,端口号任意一个跟当前页面不一致时,则会出现跨域请求拦截。

浏览器跨域有什么用?

同源策略限制了浏览器无法跨域读取 Cookie/LocalStorage/SessionStorage 或操作 DOM,主要为防止恶意网站窃取隐私。例如,你登录网银后访问黑客网站,若无同源策略,黑客可能用你的Cookie冒充操作。

浏览器跨域的最佳实践?

  1. CORS,通过预检机制(类似签证制度,有的国家需要申请,有的国家免签),将请求分为简单请求和需预检请求,如果是简单请求,直接处理。如果是复杂请求,先发出一个预检请求OPTIONS,就像申请签证,通过后才执行真实请求。
  • 为什么要有预检机制? 比如用户想发起 DELETE/PUT 等非简单请求操作,可能会直接操作数据,所以需要浏览器通过预检请求确认后端服务是否支持用户操作。

  • 预检机制如何区分普通请求和预检请求? 普通请求:1. 请求方法只能是 GET/HEAD/POST 2. Content-Type 仅支持:application/x-www-form-urlencoded、multipart/form-data、text/plain 3. 浏览器会检查请求头和方法的"安全性",任何非标准行为(如添加Authorization头)都会触发预检请求

  • CORS 具体如何实现? 后端在收到预检请求的时候,在响应头中加入 Access-Control-Allow-*.

Access-Control-Allow-Origin 请求源
Access-Control-Allow-Methods 请求方法
Access-Control-Allow-Headers 请求头
Access-Control-Max-Age 在一定时间内相同请求不需重复预检,提升性能
Access-Control-Allow-Private-Network: true专用网络访问​,从公网访问内网资源(如localhost)时,Chrome要求额外预检确认,服务器需返回
Access-Control-Allow-Credentials 允许携带认证信息,注意如果携带了认证信息,那么请求源不能设置为 *,即如果携带了 Cookie,则必须指定明确的请求源地址
  1. 跨域请求拦截是浏览器的限制,如果通过 nginx 反向代理(类似菜鸟驿站转交快递,用户无需直接面对快递员)转发可以解决
  2. 通过浏览器插件或者禁用其安全特性,也可在开发阶段解决跨域问题
  3. 其它方案,postMessage(跨窗口 iframe 通信),JSONP(只支持 GET)
  4. 如果 canvas 无法读取和导出图片,通过 window.onerror 统计错误时,只有 Script Error,都表示跟跨域相关,需要设置 crossorigin="anonymous",(对于需要凭证的图片,需要设置crossorigin="use-credentials"),且响应头添加 Access-Control-Allow-Origin: *

扩展内容

  1. 反向代理如何配置?细节:Nginx反向代理配置中,proxy_pass后是否有斜杠会影响URL重写规则。例如proxy_pass http://api.example.com/;会将/api/user转发为http://api.example.com/user,而无斜杠则会保留/api路径
  2. 配置 chrome 禁用跨域:--disable-web-security --user-data-dir=任意文件夹路径