1.https://example.com/ 请求https://example.com/redirect,此时的Sec-Fetch-Site 是same-origin;
2.https://example.com/redirect重定向到https://subdomain.example.com/redirect,此时的Sec-Fetch-Site 是same-site (因为是一级请求二级域名);
3.https://subdomain.example.com/redirect重定向到https://example.net/redirect,此时的Sec-Fetch-Site 是cross-site (因为https://example.net/和https://example.com&https://subdomain.example.com/是不同站点);
4.https://example.net/redirect重定向到https://example.com/,此时的Sec-Fetch-Site 是cross-site(因为重定向地址链里包含了https://example.net/);
含义:
取值是一个Boolean类型的值,true(?1)表示导航请求由用户激活触发(鼠标点击/键盘),false(?0)表示导航请求由用户激活以外的原因触发;
取值范围:
?0
?1
说明:
请求头只会在导航请求情况下携带,导航请求包括document , embed , frame , iframe , or object ;
了解了上面是个请求头的含义之后,我们就可以根据项目实际情况来制定安全策略了,例如google I/O提供的一个示例:
# Reject cross-origin requests to protect from CSRF, XSSI & other bugs def allow_request(req): # Allow requests from browsers which don't send Fetch Metadata if not req['sec-fetch-site']: return True # Allow same-site and browser-initiated requests if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'): return True # Allow simple top-level navigations from anywhere if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET': return True return False1.浏览器不支持Sec-Fetch-*请求头,则不做处理;
2.容许sec-fetch-site为same-origin, same-site, none三种之一的请求;
3.容许sec-fetch-mode为navigate且get请求的方法;
4.容许部分跨域请求,可设置白名单进行匹配;
5.禁止其他非导航的跨域请求,确保由用户直接发起;
在使用Fetch Metadata Request Headers时,还需要注意Vary响应头的正确设置,Vary这个响应头是干嘛的呢,其实就是缓存的版本控制,当客户端请求头中的值包含在Vary中时,就会去匹配对应的缓存版本(如果失效就会同步资源),因此针对不同的请求,能提供不同的缓存数据,可以理解为差异化服务,说明白了Vary响应头之后,就明白了Fetch Metadata Request Headers与Vary的影响关系了,因为要确保缓存能正确处理携带Sec-Fetch-*请求头的客户端响应,例如Vary: Accept-Encoding, Sec-Fetch-Site,因此有没有携带Sec-Fetch-Site将会对应两个缓存版本。
参考资料:https://developer.mozilla.org/zh-CN/docs/Web/API/Request/mode
https://web.dev/fetch-metadata/
福禄ICH·架构组 福袋