3.Referer理解错误导致的跨域

在前后端分离的情况下,大多数请求都是跨域请求。

组里的Nodejs Koa服务CORS不知道在网上参考哪个倒霉博客,在Referer上取CORS的值,差不多代码如下:

1
ctx.set('Access-Control-Allow-Origin', ctx.header.referer.slice(0, -1));

Referer 有个规则,#之后的会丢掉(e.g. #section),顺便说一句鉴权的也不行(e.g. https://username:password@example.com)。Currently 单页应用大行其道,hash路由下,只会返回Origin。

Referer为 https://app.example.com/ 时把CORS设为 https://app.example.com。刚开始岁月安好,符合预期。

问题出在当用户访问 https://app.example.com/page.html 时请求 https://api.example.com/getData,跨域了,。在不同浏览器下(严谨点说是不同的 Referrer-Policy下)会展示为

1
2
3
4
5
no-referrer-when-downgrade 
https://app.example.com/page.html

origin-when-cross-origin
https://app.example.com/

在之前默认值为 no-referrer-when-downgrade,悄咪咪的,谷歌粑粑把默认值改成了 strict-origin-when-cross-origin。这导致所有跨域网站的Referer都会变成Origin。

Chrome plans to switch its default policy from no-referrer-when-downgrade to strict-origin-when-cross-origin, starting in version 85.From developers.google.com)

However,safari浏览器还是no-referrer-when-downgrade,这意味着尽管同一个页面,referer可能在 safari下为 https://app.example.com/page.html 而在chrome下为 https://app.example.com/,所以用Referer是个愚蠢的选择,改成使用Origin来判断。

1
2
3
if (/^(.+?)\.example\.com$/.test(ctx.header.origin)) {
ctx.set('Access-Control-Allow-Origin', ctx.header.origin);
}

Reference

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
https://developers.google.com/web/updates/2020/07/referrer-policy-new-chrome-default