如何处理应作为 https 保护的网站中的混合内容?
How to deal with mixed content in a website which should be secured as https?
我正在服务器 A 上建立一个网站(已注册域名),供人们创建和 运行 他们的 "apps"。
这些 "apps" 实际上是 docker 容器 运行 在服务器 B 上,在容器中,有一个可以直接访问的小型网络应用程序,如:
http://IP_ADDR_OF_SERVER_B:PORT
PORT 是一个随机的大数字,映射到 docker 容器。
现在我可以让 SSL 证书在服务器 A 上工作,这样它就可以通过访问正常工作:
https://DOMAIN_NAME_OF_SERVER_A
问题是,我像上面一样通过访问"http"将"apps"封装在iframe中,因此我的浏览器(Chrome)拒绝打开它并报告错误:
Mixed Content: The page at 'https://DOMAIN_NAME_OF_SERVER_A/xxx' was loaded over HTTPS, but requested an insecure resource 'http://IP_ADDR_OF_SERVER_B:PORT/xxx'. This request has been blocked; the content must be served over HTTPS.
那么,我该如何处理这样的问题呢?
我是一个全栈新手,如果你能分享一些关于如何建立一个健康的https网站的知识,同时以适当的方式解决这样的问题,我将不胜感激。
补充说明
好的,我想我只是抛出了问题的大纲,这里有更多细节。
我看到使用 https 发送 iframe 请求是完整且直接的,这样我就不会再感到困惑了。
不过麻烦的是,由于所有的"apps"都是动态的created/removed,看来每一个都需要准备很多证书。
自签名证书是否会在不被浏览器阻止或投诉的情况下工作?还是我有办法用一个 SSL 证书为所有 "apps" 提供服务?
软件环境
服务器 A: 运行 node.js 网站监听端口 5000 并使用 Nginx proxy_pass.
server {
listen 80;
server_name DOMAIN_NAME_OF_SERVER_A;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:5000;
}
}
server {
listen 443;
server_name DOMAIN_NAME_OF_SERVER_A;
ssl on;
ssl_certificate /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_A.cer;
ssl_certificate_key /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_A.key;
ssl_session_timeout 5m;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:5000;
}
}
服务器 B: 运行 node.js 应用程序监听不同的随机大端口号,例如 50055,在创建 "apps" 时动态分配. (事实上 ,这些应用程序 运行ning 在 docker 容器中,而我认为这无关紧要)如果需要,可以 运行 Nginx。
服务器 A 和 服务器 B 在 public 流量中相互交谈。
解决方案
正如所有答案一样,尤其是来自@eawenden 的答案,我需要一个反向代理来实现我的目标。
此外,我还做了几件事:
1. 为服务器B分配一个域名以使用letsencrypt证书。
2.代理预定义url到特定端口。
因此我在 服务器 B 上使用 nginx 设置了一个反向代理服务器,代理所有请求,如:
https://DOMAIN_NAME_OF_SERVER_B/PORT/xxx
到
https://127.0.0.1:PORT/xxx
Ps:服务器 B
上的 nginx 反向代理配置
server {
listen 443;
server_name DOMAIN_NAME_OF_SERVER_B;
ssl on;
ssl_certificate /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_B.cer;
ssl_certificate_key /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_B.key;
ssl_session_timeout 5m;
rewrite_log off;
error_log /var/log/nginx/rewrite.error.log info;
location ~ ^/(?<port>\d+)/ {
rewrite ^/\d+?(/.*) break;
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
因此一切似乎都按预期工作!
再次感谢所有的回答者。
错误消息几乎告诉了您解决方案。
This request has been blocked; the content must be served over HTTPS.
如果主页通过 HTTPS 加载,则所有其他页面内容(包括 iframe)也应通过 HTTPS 加载。
原因是不安全(非 HTTPS)流量在传输过程中可能会被篡改,可能会被更改为包含更改安全内容的恶意代码。 (例如,考虑一个登录页面,其中注入了窃取用户 ID 和密码的脚本。)
== 更新以反映 "supplemental information" ==
正如我所说,页面上的所有内容都需要通过 HTTPS 加载。是的,自签名证书可以工作,但有一些注意事项:首先,您必须告诉浏览器允许它们,其次,它们实际上只适合在开发环境中使用。 (您不想让用户养成点击安全警告的习惯。)
@eawenden 的回答提供了一种使所有内容看起来都来自单个服务器的解决方案,从而提供了一种使用单个证书的方法。请注意,反向代理是一个有点高级的主题,在生产环境中设置起来可能更困难。
如果您控制所有 iframe 的服务器,另一种方法可能是使用通配符 SSL 证书。例如,这将针对 *.mydomain.com 发布,并且适用于 www.mydomain.com、subsite1.mydomain.com、subsite2.mydomain 等,适用于 mydomain.com 下的所有内容]
正如其他人所说,您应该通过 HTTPS 提供所有内容。
您可以使用 http 代理来执行此操作。这意味着服务器 A 将处理 HTTPS 连接并通过 HTTP 将请求转发到服务器 B。 HTTP 然后将响应发送回服务器 A,服务器 A 将更新响应 headers 使其看起来像是来自服务器 A 本身并将响应转发给用户。
您可以让服务器 B 上的每个应用程序在域 A 上的 url 上可用,例如 https://www.domain-a.com/appOnB1 and https://www.domain-a.com/appOnB2。然后代理会将请求转发到服务器 B 上的正确端口。
对于 Apache,这意味着每个应用程序的配置中有两行额外的内容:
ProxyPass "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"
ProxyPassReverse "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"
第一行将确保 Apache 将此请求转发到服务器 B,第二行将确保 Apache 更改 HTTP 响应中的地址 headers 使其看起来像是来自服务器的响应A 而不是服务器 B.
由于您需要使此代理动态化,因此在服务器 A 上的 NodeJS 应用程序中设置此代理可能更有意义,因为该应用程序可能已经了解服务器 B 上的不同应用程序. 我不是 NodeJS 专家,但快速搜索 https://github.com/nodejitsu/node-http-proxy 看起来它可以解决问题并且看起来是一个维护良好的项目。
尽管总体思路保持不变:您可以使用服务器 A 的 HTTPS set-up 使用代理通过服务器 A 访问服务器 B 上的应用程序。对于用户来说,服务器 B 上的所有应用程序看起来都托管在域 A 上。
设置完成后,您可以使用 https://DOMAIN_NAME_OF_SERVER_A/fooApp
作为 iFrame 的 url 通过 HTTPS 加载应用程序。
警告:只有当您可以在内部路由此流量时才应执行此操作(服务器 A 和 B 可以在同一网络上相互访问),否则流量可能会在它从服务器 A 到服务器 B 的方式。
最好的方法是使用反向代理 (Nginx supports them) 提供对 docker 容器的访问:
A reverse proxy server is a type of proxy server that typically sits
behind the firewall in a private network and directs client requests
to the appropriate backend server. A reverse proxy provides an
additional level of abstraction and control to ensure the smooth flow
of network traffic between clients and servers.
- Source
分配域名或仅使用反向代理的 IP 地址并创建可信证书(Let's Encrypt 提供免费证书)。然后您可以使用受信任的证书通过 HTTPS 连接到反向代理,它将处理连接到正确的 Docker 容器。
这是专门针对 Docker 的此类设置示例:https://github.com/jwilder/nginx-proxy
我在动态请求中遇到混合内容问题
add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
这解决了我的 ngnix 服务器问题
我正在服务器 A 上建立一个网站(已注册域名),供人们创建和 运行 他们的 "apps"。
这些 "apps" 实际上是 docker 容器 运行 在服务器 B 上,在容器中,有一个可以直接访问的小型网络应用程序,如:
http://IP_ADDR_OF_SERVER_B:PORT
PORT 是一个随机的大数字,映射到 docker 容器。 现在我可以让 SSL 证书在服务器 A 上工作,这样它就可以通过访问正常工作:
https://DOMAIN_NAME_OF_SERVER_A
问题是,我像上面一样通过访问"http"将"apps"封装在iframe中,因此我的浏览器(Chrome)拒绝打开它并报告错误:
Mixed Content: The page at 'https://DOMAIN_NAME_OF_SERVER_A/xxx' was loaded over HTTPS, but requested an insecure resource 'http://IP_ADDR_OF_SERVER_B:PORT/xxx'. This request has been blocked; the content must be served over HTTPS.
那么,我该如何处理这样的问题呢?
我是一个全栈新手,如果你能分享一些关于如何建立一个健康的https网站的知识,同时以适当的方式解决这样的问题,我将不胜感激。
补充说明
好的,我想我只是抛出了问题的大纲,这里有更多细节。
我看到使用 https 发送 iframe 请求是完整且直接的,这样我就不会再感到困惑了。
不过麻烦的是,由于所有的"apps"都是动态的created/removed,看来每一个都需要准备很多证书。
自签名证书是否会在不被浏览器阻止或投诉的情况下工作?还是我有办法用一个 SSL 证书为所有 "apps" 提供服务?
软件环境
服务器 A: 运行 node.js 网站监听端口 5000 并使用 Nginx proxy_pass.
server {
listen 80;
server_name DOMAIN_NAME_OF_SERVER_A;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:5000;
}
}
server {
listen 443;
server_name DOMAIN_NAME_OF_SERVER_A;
ssl on;
ssl_certificate /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_A.cer;
ssl_certificate_key /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_A.key;
ssl_session_timeout 5m;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:5000;
}
}
服务器 B: 运行 node.js 应用程序监听不同的随机大端口号,例如 50055,在创建 "apps" 时动态分配. (事实上 ,这些应用程序 运行ning 在 docker 容器中,而我认为这无关紧要)如果需要,可以 运行 Nginx。
服务器 A 和 服务器 B 在 public 流量中相互交谈。
解决方案
正如所有答案一样,尤其是来自@eawenden 的答案,我需要一个反向代理来实现我的目标。
此外,我还做了几件事:
1. 为服务器B分配一个域名以使用letsencrypt证书。
2.代理预定义url到特定端口。
因此我在 服务器 B 上使用 nginx 设置了一个反向代理服务器,代理所有请求,如:
https://DOMAIN_NAME_OF_SERVER_B/PORT/xxx
到
https://127.0.0.1:PORT/xxx
Ps:服务器 B
上的 nginx 反向代理配置server {
listen 443;
server_name DOMAIN_NAME_OF_SERVER_B;
ssl on;
ssl_certificate /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_B.cer;
ssl_certificate_key /etc/nginx/ssl/DOMAIN_NAME_OF_SERVER_B.key;
ssl_session_timeout 5m;
rewrite_log off;
error_log /var/log/nginx/rewrite.error.log info;
location ~ ^/(?<port>\d+)/ {
rewrite ^/\d+?(/.*) break;
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
因此一切似乎都按预期工作!
再次感谢所有的回答者。
错误消息几乎告诉了您解决方案。
This request has been blocked; the content must be served over HTTPS.
如果主页通过 HTTPS 加载,则所有其他页面内容(包括 iframe)也应通过 HTTPS 加载。
原因是不安全(非 HTTPS)流量在传输过程中可能会被篡改,可能会被更改为包含更改安全内容的恶意代码。 (例如,考虑一个登录页面,其中注入了窃取用户 ID 和密码的脚本。)
== 更新以反映 "supplemental information" ==
正如我所说,页面上的所有内容都需要通过 HTTPS 加载。是的,自签名证书可以工作,但有一些注意事项:首先,您必须告诉浏览器允许它们,其次,它们实际上只适合在开发环境中使用。 (您不想让用户养成点击安全警告的习惯。)
@eawenden 的回答提供了一种使所有内容看起来都来自单个服务器的解决方案,从而提供了一种使用单个证书的方法。请注意,反向代理是一个有点高级的主题,在生产环境中设置起来可能更困难。
如果您控制所有 iframe 的服务器,另一种方法可能是使用通配符 SSL 证书。例如,这将针对 *.mydomain.com 发布,并且适用于 www.mydomain.com、subsite1.mydomain.com、subsite2.mydomain 等,适用于 mydomain.com 下的所有内容]
正如其他人所说,您应该通过 HTTPS 提供所有内容。
您可以使用 http 代理来执行此操作。这意味着服务器 A 将处理 HTTPS 连接并通过 HTTP 将请求转发到服务器 B。 HTTP 然后将响应发送回服务器 A,服务器 A 将更新响应 headers 使其看起来像是来自服务器 A 本身并将响应转发给用户。
您可以让服务器 B 上的每个应用程序在域 A 上的 url 上可用,例如 https://www.domain-a.com/appOnB1 and https://www.domain-a.com/appOnB2。然后代理会将请求转发到服务器 B 上的正确端口。
对于 Apache,这意味着每个应用程序的配置中有两行额外的内容:
ProxyPass "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"
ProxyPassReverse "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"
第一行将确保 Apache 将此请求转发到服务器 B,第二行将确保 Apache 更改 HTTP 响应中的地址 headers 使其看起来像是来自服务器的响应A 而不是服务器 B.
由于您需要使此代理动态化,因此在服务器 A 上的 NodeJS 应用程序中设置此代理可能更有意义,因为该应用程序可能已经了解服务器 B 上的不同应用程序. 我不是 NodeJS 专家,但快速搜索 https://github.com/nodejitsu/node-http-proxy 看起来它可以解决问题并且看起来是一个维护良好的项目。
尽管总体思路保持不变:您可以使用服务器 A 的 HTTPS set-up 使用代理通过服务器 A 访问服务器 B 上的应用程序。对于用户来说,服务器 B 上的所有应用程序看起来都托管在域 A 上。
设置完成后,您可以使用 https://DOMAIN_NAME_OF_SERVER_A/fooApp
作为 iFrame 的 url 通过 HTTPS 加载应用程序。
警告:只有当您可以在内部路由此流量时才应执行此操作(服务器 A 和 B 可以在同一网络上相互访问),否则流量可能会在它从服务器 A 到服务器 B 的方式。
最好的方法是使用反向代理 (Nginx supports them) 提供对 docker 容器的访问:
A reverse proxy server is a type of proxy server that typically sits behind the firewall in a private network and directs client requests to the appropriate backend server. A reverse proxy provides an additional level of abstraction and control to ensure the smooth flow of network traffic between clients and servers.
- Source
分配域名或仅使用反向代理的 IP 地址并创建可信证书(Let's Encrypt 提供免费证书)。然后您可以使用受信任的证书通过 HTTPS 连接到反向代理,它将处理连接到正确的 Docker 容器。
这是专门针对 Docker 的此类设置示例:https://github.com/jwilder/nginx-proxy
我在动态请求中遇到混合内容问题
add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
这解决了我的 ngnix 服务器问题