chrome 同站策略(samesite)问题及解决方案

一、同站策略问题

chrome自版本80之后,出现了所谓同站策略问题。

即,在A页面请求B页面,如果chrome发现它们不是同一个站点的话,就不传cookie给B页面所在的服务器。众所周知,原本cookie是会附在浏览器到服务器的每个请求(request)里的,仿佛这是理所应当,自然而然的,现在好了,chrome区分情况,不一定允许这么干了。

这样的后果是什么呢?就是有些功能以前没问题的,现在不行了。拿我们项目来说,原本我们有些WEB项目,会用iframe将其他项目的一些页面嵌进去,看上去就好像同一个系统一样,这叫界面集成吧,很正常的行为。两边项目的自动登录什么的都搞好了,一直运行正常。后来升级了浏览器,发现嵌进去的页面数据出不来。程序没有做任何更改,最后发现是账号登录问题,嵌进去的页面始终处于无法登录状态,从而导致获取不了数据。

具体来说,cookie是由服务器分配给浏览器的,相当于给了浏览器一个访问凭证。浏览器每次访问服务器的时候,都会带上这些个凭证。现在由于浏览器策略改变,嵌进去的页面与服务器交互的时候,无法带上cookie,服务器检索不到这个凭证,就每次都给页面分配一个新的cookie,前后对应不上,当然就登录不了了。

其实,chrome一直有这个同站策略,Chrome 51 开始,浏览器的 Cookie 新增加了一个SameSite属性,用来防止 CSRF 攻击和用户追踪。SameSite可以设置三个值:

Strict
Lax
None

Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。

Lax规则稍稍放宽,分情况处理,具体如下
在这里插入图片描述
None的话,就不做是否同站的检查和限制。以前,chrome默认SameSite=None,80版本以后则默认是Lax了。这也是为什么chrome升级以后,程序突然异常的缘故。

二、解决方案

1、修改浏览器设置
这种方法简单粗暴,直接将浏览器的SameSite的属性设置回到以前的None状态。姑且不论用户是否愿意,但单就每台机的浏览器都要进行设置而言,已经违背了BS架构应用的最大优点,就是客户端无须安装部署这一宗旨。所以我觉得这是一个实在没有别的办法的时候,才不得不采取的措施。

设置方法如下:

1)chrome地址栏输入chrome://flags
2)通过禁用“SameSite by default cookies”和“Cookies without SameSite must be secure”功能开关
3)重新启动浏览器

2、Set-Cookie:SameSite=None
就是将response的header设置Set-Cookie:SameSite=None。

Set-Cookie: SameSite=None; Secure

Set-Cookie

这里有个疑问,谁来设置这个set-cookie?以上述我们项目为例,A项目的页面用iframe嵌入了B项目的页面,是A项目来设置set-cookie还是B项目?应当是B。因为嵌入的是B项目的页面,response来自B服务器,A使不上劲。

注意必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。这意味着,B项目必须采用https?不过我试了几下,发现没什么效果。也许我的A项目本身是http,需要A和B都为https才可以?不清楚。

不过有个设置 SameSite 为 none的实例。以 Adobe 网站为例:https://www.adobe.com/sea/,查看请求可以看到:
在这里插入图片描述
3、Nginx做网站映射
(我习惯叫映射,但一般叫做转发)
SameSite策略针对的是不同站的请求,同站就没有问题。那么A项目嵌入B项目的页面,将B站点映射为同一个站点不就好了?同站与同源(非跨域)是不一样的,我感觉同站比同源要严格一些。解决同源问题,即跨域问题,顶级域名相同就可以了;同站的话,域名要保持一致,端口可以不一样,所以如果映射为同站,可以域名或IP相同,端口不同。

同站与同源的区别很复杂,可以看看这里。

映射站点的不二选择,当然是Nginx了。比如A项目在我本地,http://localhost:8081,现在嵌入了B项目的页面,B项目地址为http://192.168.0.248:8082/,现在需要映射为http://localhost:8082。

1)设置Nginx的配置,如

http {
    server {
		listen       8082;  
        server_name  localhost;  
		location / {
			proxy_pass http://192.168.0.248:8082/;
		}
    }
}

2)运行nginx

映射之后,A项目嵌入的B项目页面改用新地址,浏览器就以为它们是同一站点,放松警惕,该干啥干啥了。

三、总结

谷歌浏览器的这种同站策略是一种傲慢,虽然它也允许B服务器设置SameSite=None,但要跟https绑定。网络有互联网和局域网之分,安全从来都是相对的,要跟付出的代价一起衡量。在局域网中,A、B项目都是自己开发的,嵌入有何不可?https的话,要制作证书,本身是非常繁琐的。幸好其他浏览器还没有跟进。


2022.06.09
采用https的话,就算浏览器无法识别证书,数据仍然是加密传输的,安全可以得到保证。

Cookie 的 SameSite 属性
浏览器系列之 Cookie 和 SameSite 属性

<think>嗯,用户之前问过关于ECharts的使用,现在又问前端跨域问题解决方案和代码。看来他们可能在开发前端项目,遇到了跨域的问题,需要具体的解决办法。 首先,用户可能是在本地开发时遇到了跨域,比如用Vue或React启动了一个本地服务器,然后请求后端API时出现跨域错误。这时候他们需要知道如何配置代理或者后端设置CORS。 然后,用户可能对跨域的基本概念不太清楚,需要先解释什么是跨域,同源策略的限制。不过用户直接要解决方案和代码,可能已经知道基础,但需要具体的方法。 常见的解决方案包括:后端设置CORS,前端配置代理,JSONP,Nginx反向代理,Webpack配置代理,postMessage,修改浏览器设置等。其中,CORS和代理是比较常用的,尤其是开发环境下,前端代理很常见。 需要详细说明每种方法的适用场景和具体实现步骤,比如CORS需要后端设置响应头,前端代理则是在开发服务器中配置,避免直接请求后端地址导致跨域。 还要注意安全性问题,比如CORS中不要滥用Access-Control-Allow-Origin为*,生产环境应该指定具体域名。Nginx配置反向代理时也要注意路径匹配和头信息传递。 另外,用户可能需要代码示例,比如如何在Express中设置CORS,Vue的vue.config.js怎么配代理,或者Nginx的配置片段。JSONP的例子虽然现在用的少,但可能某些旧项目还在用,也需要提及。 可能需要区分开发环境和生产环境的解决方案,开发时用代理,生产用Nginx或者后端处理。同时,提醒用户JSONP只支持GET请求,其他方法有局限性。 还要考虑用户的技术栈,比如他们之前用Vue3和ECharts,可能更熟悉Vue的代理配置,所以提供vue.config.js的例子会更实用。 总结下来,回答的结构应该是先解释跨域原因,再列出各种解决方案,每种方案给出适用场景、实现步骤和代码示例。最后给出最佳实践建议,帮助用户根据具体情况选择合适的方法。</think>以下是前端跨域问题的完整解决方案及代码实现指南,结合不同开发场景提供多种解决方式: --- ### 一、跨域本质解析 **同源策略限制**:当协议、域名、端口任一不同时触发跨域拦截 **典型错误**:`Access-Control-Allow-Origin`缺失导致的`No 'Access-Control-Allow-Origin'`错误 --- ### 二、解决方案分类 #### 1. 后端协作方案 **(1) CORS跨域资源共享** ```javascript // Node.js Express示例 app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "http://localhost:8080") // 精确白名单 res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS") res.header("Access-Control-Allow-Headers", "Content-Type,Authorization") res.header("Access-Control-Allow-Credentials", "true") // 允许携带cookie req.method === 'OPTIONS' ? res.sendStatus(200) : next() }) ``` **(2) Nginx反向代理** ```nginx # nginx.conf配置片段 server { listen 80; server_name api.yourdomain.com; location / { proxy_pass http://localhost:3000; # 后端真实地址 add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods *; add_header Access-Control-Allow-Headers *; if ($request_method = 'OPTIONS') { return 204; } } } ``` --- #### 2. 纯前端方案 **(1) 开发环境代理(Webpack/Vite)** ```javascript // vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://backend-service:3000', changeOrigin: true, pathRewrite: { '^/api': '' } } } } } ``` **(2) JSONP(仅限GET请求)** ```javascript function jsonp(url, callback) { const script = document.createElement('script') script.src = `${url}?callback=${callback}` document.body.appendChild(script) } // 全局定义回调函数 window.handleResponse = (data) => { console.log('Received:', data) } // 调用示例 jsonp('http://api.example.com/data', 'handleResponse') ``` **(3) postMessage跨窗口通信** ```javascript // 子窗口发送消息 window.parent.postMessage({ type: 'data', content: 'payload' }, 'http://parent-domain.com') // 主窗口监听 window.addEventListener('message', (event) => { if (event.origin !== 'http://child-domain.com') return console.log('Received:', event.data) }) ``` --- ### 三、特殊场景解决方案 #### 1. WebSocket跨域 ```javascript const ws = new WebSocket('ws://socket-server.com') // 协议升级自动跨域 ws.onopen = () => { ws.send('Connection established') } ``` #### 2. 跨域图片资源 ```html <img crossorigin="anonymous" src="http://external.com/image.jpg"> <!-- 需配合服务端设置Access-Control-Allow-Origin --> ``` #### 3. 本地文件协议跨域 ```bash # Chrome启动参数(开发测试用) chrome.exe --disable-web-security --user-data-dir="C:/temp" ``` --- ### 四、安全增强措施 1. **CORS白名单控制** ```javascript const allowOrigins = ['https://your-domain.com', 'http://localhost:8080'] app.use((req, res, next) => { const origin = req.headers.origin if (allowOrigins.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin) } // ...其他配置 }) ``` 2. **CSRF Token验证** ```javascript // 前端在每个请求头携带token axios.interceptors.request.use(config => { config.headers['X-CSRF-Token'] = getCookie('csrfToken') return config }) ``` --- ### 五、最佳实践建议 1. **开发环境**:优先使用Webpack/Vite代理 2. **生产环境**: - 部署同域服务 - 必须跨域时使用Nginx反向代理+CORS 3. **敏感接口**: - 添加`Access-Control-Allow-Credentials: true` - 配合SameSite Cookie策略 4. **移动端Hybrid开发**: - 使用WebView自定义协议拦截 - 或通过Native Bridge中转请求 --- ### 六、调试工具验证 ```javascript // 使用fetch测试CORS配置 fetch('http://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ test: 1 }) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('CORS Error:', error)) ``` --- **方案选择决策树**: 1. 是否控制后端 → 是:CORS/Nginx 2. 仅前端控制 → 开发用代理,生产用JSONP/postMessage 3. 需要双向通信 → WebSocket 4. 旧系统兼容 → JSONP 通过合理组合这些方案,可以解决99%的前端跨域问题,建议优先采用标准化的CORS方案+反向代理模式。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值