推荐阅读
注意,我们整篇文章都在讨论跨域,相同域下的资源访问是没有这些问题的。
前端很多时候,会需要请求跨域的资源(接口或图片等)。
这时候,你就需要用到跨域资源共享(CORS)了,你可以通过在 Response header
上添加 Access-Control-*
系列字段,明确声明你的资源的访问策略。如:
Access-Control-Allow-Origin
限制仅某些域才能访问Access-Control-Allow-Methods
只接受特定方法(Get
、Post
等)的访问Access-Control-Allow-Credentials
请求要不要携带Credentials
(Credentials
可以是 cookies
、authorization headers
或 TLS client certificates
)此外,我们知道 Cookie
在网络传输中扮演着很重要的角色,你希望在各种请求中控制 Cookie
是否发送。
此时,虽然 Access-Control-Allow-Credentials
可以控制跨域请求是否允许携带凭据,但它只能在 CORS
请求方面起作用。
如果一个恶意网站用 iframe
嵌套了你的网站,恶意网站有可能会误导用户执行特定的操作。此时用户的操作携带 Cookie
的话,将会很危险。
别担心,有 SameSite Cookie。
SameSite Cookie
属性是一种更广泛的机制,可以控制在所有类型的跨站点请求(包括页面导航、图片加载、iframe 加载等)中是否发送 Cookie。
建议看看阮一峰的 Cookie 的 SameSite 属性,介绍得很清楚。
Chrome
默认的 SameSite
是 Lax
,是比较严格的,只有一些通常意义上不会造成资源修改的操作才允许携带 Cookie
,最大限度地保障了用户的网络安全。
我们在业务中经常碰到的问题是,两个域都是我自己的,为什么这个跨站请求没有携带 Cookie
呢?
此时,我们服务端需要在 Response header
set-Cookie
字段中,声明 SameSite=None
set-Cookie: xxx=xxx;Domain=.your-target.site;SameSite=None;Secure
这样,*.your-target.site
就能附带 Cookie
访问你的资源了。
通常,服务提供者是不会随便对所有域设置
SameSite=None
的,通常只会对特定的几个域(他自己持有的或信任的域)设置SameSite=None
。
假设 third-party.site
是一个很牛哔的站点,它提供了网络基础设施,你今天访问了 A/B/C/D/E
各种网站,都引用了 third-party.site
的资源。
如果浏览器允许随便携带 Cookie
,那就糟了,third-party.site
就知道你的访问记录了。这就叫跨站跟踪。
所以,Chrome
默认 SameSite=Lax
,很多请求都不允许携带 Cookie
,尽可能保护用户的隐私。
当然,你说如果
third-party.site
设置所有域都SameSite=None
,那不就能跟踪了吗?确实,这样是能跟踪了,但是它自身也冒着其他的一些安全风险,就不赘述了。
我本地开发,SameSite
有问题啊
本地开发的时候,我们可能需要在其他设备上访问本机起的服务,通常是访问 http://192.168.x.x
,这时候就有问题了:
SameSite=None
必须要 Secure
才能生效,可是 http://192.168.x.x
不是一个安全的域SameSite=Lax
又会导致一些跨域请求被阻止这时候可以再起一个 https
服务,代理到 http
的端口上,其他设备上就能访问 https
,SameSite=None
就能生效了。
推荐一个方便地起
https
的命令行工具:local-ssl-proxy
我不是允许跨域了吗?怎么请求还是被阻止了?
注意看看 Request header
是不是添加了一些自定义的字段,如果有,需要在 Response header
Access-Control-Expose-Headers
中添加该字段。
注意看
devtool -> Network
或devtool -> Console
tab 中的报错信息,一般报错信息会详细地告诉你请求为什么被阻止。
P.S. 前段时间写的 《为什么 Chrome 要禁止跨域》
被我不小心误删了,才发现数据库备份脚本权限有问题,一直没有执行。删除也是物理删除,没有做假删除,直接找不回来了。尬了,只能重新写了。。。
如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。
对于转载作品,如需二次转载,请遵循原作许可。