跨域嵌入iframe的cookie写入问题

X-Frame-Options

设置网页允许被跨域嵌入iframe

类似这样:

1
2
3
4
5
location /resource/page/{
add_header X-Frame-Options "ALLOW-FROM http://activity.10jqka.com.cn/";
add_header Content-Security-Policy "frame-ancestors http://activity.10jqka.com.cn;" always;
alias /var/www/resource/front/public/test/;
}

注意事项

注意:
1、在高版本的Chrome中,已经不允许指定X-Frame-Options的域名了,浏览器会报错:无法识别这个指令
因此目前建议使用Content-Security-Policy来替代X-Frame-Options

2、如果使用了nginx的别名(alias),add_header必须设置在alias之前,否则不生效

3、如需设置多个域名,必须用空格分割:
add_header Content-Security-Policy “frame-ancestors http://activity.10jqka.com.cn http://t.zhouchangju.com;” always;

注意事项

HTTP 接口不支持 SameSite=none

如果你想加 SameSite=none 属性,那么该 Cookie 就必须同时加上 Secure 属性,表示只有在 HTTPS 协议下该 Cookie 才会被发送。

需要 UA 检测,部分浏览器不能加 SameSite=none

IOS 12 的 Safari 以及老版本的一些 Chrome 会把 SameSite=none 识别成 SameSite=Strict,所以服务端必须在下发 Set-Cookie 响应头时进行 User-Agent 检测,对这些浏览器不下发 SameSite=none 属性

配置

因为用户的请求是经过Nginx转发到Egg.js服务的,从Nginx到Egg.js这一级走的是http协议,因此如果不明确告知程序的话,会报这个错误:

Cannot send secure cookie over unencrypted connection

Nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
upstream resource-server {
server 127.0.0.1:7001;
keepalive 64;
}

location /test/{
root /var/www/resource/server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
#这是关键的设置
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_max_temp_file_size 0;
#转发到Egg.js的服务
proxy_pass http://resource-server/;
proxy_redirect off;
proxy_read_timeout 240s;
client_max_body_size 1000m;
}

注意:如果有多级Nginx,要检查下每一级Nginx是否都传递了这个头。

Nginx中也是可以直接设置samesite的,可以参考这个文章:

https://www.ubisecure.com/technical-announcements/samesite-cookies-changes/

Egg.js

如果不想在Nginx中设置samesite,而是想在Egg.js中何止,则需要在/config/config.default.js中做如下设置:

1
2
3
4
5
6
7
config.cookies = {
sameSite: 'None',
secure: true,
}

config.proxy = true;
config.protocolHeaders = 'X-Real-Proto, X-Forwarded-Proto';

验证

设置如果OK,在请求头中应该可以看到类似这样的结果:

1
2
set-cookie: email=456; path=/; max-age=86400; expires=Thu, 10 Dec 2020 12:20:16 GMT; samesite=none; secure; httponly
set-cookie: email.sig=lbCwid0RouwoBOROK1fpb4hHGxZaDfFTcZj1dfr1Lcc; path=/; max-age=86400; expires=Thu, 10 Dec 2020 12:20:16 GMT; samesite=none; secure; httponly

The request client is not a secure context and the resource is in more-private address space `privat

https://blog.csdn.net/lrx03145616256/article/details/121097483

原因

Chrome浏览器94及以后的版本,引入了弃用试验Block insecure private network requests,就是当目标站点的ip地址比请求发起者的ip地址更加私密时,会进行阻止。 http://localhost > https://abc.xxx.com > http://yyy.cn ,所以从http://yyy.cn向https://carvodpre.intra.xiaojukeji.comabc.xxx.com 发起请求会报错!

我们是大屏出现这个问题,调用链路如下:

1、安全的https://activity.10jqka.com.cn/作为大屏的iframe容器A

2、A里面以iframe的形式嵌入了不安全的https://datav.iwencai.com/epidemic-screen.html,记作页面B

3、B里面请求了安全的接口https://ehr.myhexin.com/

所以问题出在2里面。

解决方案

以下任意一种方法即可

1、使用Chrome低版本或其他浏览器。

2、将网站升级为https。

3、在Chrome浏览器地址栏搜索chrome://flags,然后在搜索框搜索Block insecure private network requests,最后将其Default改为Disabled。