How to deal with mixed content in a website which should be secured as https?

£可爱£侵袭症+ 提交于 2021-01-21 08:05:17

问题


I am building a website on server A (with domain name registered), used for people to create and run their "apps".
These "apps" are actually docker containers running on server B, in the container, there lives a small web app which can be accessed directly like:

http://IP_ADDR_OF_SERVER_B:PORT

The PORT is a random big number one which maps to the docker container. Now I can make SSL certificate working on server A, so that it works fine by accessing:

https://DOMAIN_NAME_OF_SERVER_A

The problem is, I enclosed the "apps" in iframe by accessing "http" like above, therefore my browser(Chrome) refuse to open it and report error as:

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.

So, how should I deal with such issue?
I am a full stack green hand, I'd appreciate a lot if you can share some knowledge on how to build a healthy https website while solving such problem in a proper way.


Supplementary explanation

Ok I think I just threw out the outline of the question, here goes more details.

I see it is intact and straight forward to make the iframe requests to be served with https, then it won't confuse me anymore.

However the trouble is, since all the "apps" are dynamically created/removed, it seems I'll need to prepare many certificates for each one of them.

Will self signed certificate work without being blocked or complained by the browser? Or do I have a way to serve all the "apps" with one SSL certificate?


Software environment

Server A: Running node.js website listening to port 5000 and served with 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;
    }
}

Server B: Running node.js apps listening to different random big port numbers such as 50055, assigned dynamically when "apps" are created. (In fact these apps are running in docker containers while I think it doesn't matter) Can run Nginx if needed.

Server A and Server B talk with each other in public traffic.


Solution

Just as all the answers, especially the one from @eawenden, I need a reverse proxy to achieve my goal.

In addition, I did a few more things:
1. Assign a domain name to Server B for using a letsencrypt cert.
2. Proxy predefined url to specific port.

Therefore I setup a reverse proxy server using nginx on Server B, proxy all the requests like:

https://DOMAIN_NAME_OF_SERVER_B/PORT/xxx

to

https://127.0.0.1:PORT/xxx

Ps: nginx reverse proxy config on Server B

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+?(/.*) $1 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;
    }
}

Thus everything seems to be working as expected!
Thanks again to all the answerers.


回答1:


Like others have said, you should serve all the content over HTTPS.

You could use http proxy to do this. This means that server A will handle the HTTPS connection and forward the request to server B over HTTP. HTTP will then send the response back to server A, which will update the response headers to make it look like the response came from server A itself and forward the response to the user.

You would make each of your apps on server B available on a url on domain A, for instance https://www.domain-a.com/appOnB1 and https://www.domain-a.com/appOnB2. The proxy would then forward the requests to the right port on server B.

For Apache this would mean two extra lines in your configuration per app:

ProxyPass "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"
ProxyPassReverse "/fooApp" "http://IP_ADDR_OF_SERVER_B:PORT"

The first line will make sure that Apache forwards this request to server B and the second line will make sure that Apache changes the address in the HTTP response headers to make it look like the response came from server A instead of server B.

As you have a requirement to make this proxy dynamic, it might make more sense to set this proxy up inside your NodeJS app on server A, because that app probably already has knowledge about the different apps that live on server B. I'm no NodeJS expert, but a quick search turned up https://github.com/nodejitsu/node-http-proxy which looks like it would do the trick and seems like a well maintained project.

The general idea remains the same though: You make the apps on server B accessible through server A using a proxy, using server A's HTTPS set-up. To the user it will look like all the apps on server B are hosted on domain A.

After you set this up you can use https://DOMAIN_NAME_OF_SERVER_A/fooApp as the url for your iFrame to load the apps over HTTPS.

Warning: You should only do this if you can route this traffic internally (server A and B can reach each other on the same network), otherwise traffic could be intercepted on its way from server A to server B.




回答2:


The best way to do it would be to have a reverse proxy (Nginx supports them) that provides access to the docker containers:

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

Assign a domain name or just use the IP address of the reverse proxy and create a trusted certificate (Let's Encrypt provides free certificates). Then you can connect to the reverse proxy over HTTPS with a trusted certificate and it will handle connecting to the correct Docker container.

Here's an example of this type of setup geared specifically towards Docker: https://github.com/jwilder/nginx-proxy




回答3:


The error message is pretty much telling you the solution.

This request has been blocked; the content must be served over HTTPS.

If the main page is loaded over HTTPS, then all the other page content, including the iframes, should also be loaded over HTTPS.

The reason is that insecure (non-HTTPS) traffic can be tampered with in transit, potentially being altered to include malicious code that alters the secure content. (Consider for example a login page with a script being injected that steals the userid and password.)

== Update to reflect the "supplemental information" ==

As I said, everything on the page needs to be loaded via HTTPS. Yes, self-signed certificates will work, but with some caveats: first, you'll have to tell the browser to allow them, and second, they're really only suitable for use in a development situation. (You do not want to get users in the habit of clicking through a security warning.)

The answer from @eawenden provides a solution for making all of the content appear to come from a single server, thus providing a way to use a single certificate. Be warned, reverse proxy is a somewhat advanced topic and may be more difficult to set up in a production environment.

An alternative, if you control the servers for all of the iframes, may be to use a wildcard SSL certificate. This would be issued for example for *.mydomain.com, and would work for www.mydomain.com, subsite1.mydomain.com, subsite2.mydomain, etc, for everything under mydomain.com



来源:https://stackoverflow.com/questions/41594531/how-to-deal-with-mixed-content-in-a-website-which-should-be-secured-as-https

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!