如何在 https 的 iframe 里访问 http 页面? | nginx应用实战-3

好记性不如 烂笔头,趁热记录下,给未来的自己

0 | 前言

项目需求永远是学习技术最好的动力

项目中,有这样一个业务场景,作为一个平台,可以部署用户写的各种应用,比如gradio应用,streamlit应用,也可以嵌入外部网站的url,这些应用在平台上通过嵌入 iframe 去展示。

然后,针对外部网站,有很多临时性的 demo,或者开发者不方便配置网站 https 证书的时候,往往提供的都是基于 http 协议的访问 url,如果父页面是基于 https 的话,在其嵌入 http 协议的 iframe 链接,就会报错而无法访问。

那么,面对这样的场景,我们该如何去实现呢?

1 | 思路

其实顶层 workaround 的思路就是两个方向,怎么做,可以:

  1. 在 https 的 iframe 里支持 http 的访问?
  2. 把 http 的访问转换成 https 的?

第一个方向,调研了几天,各种搜索,问GPT,得到的结论是:不行,原因如下:

  1. 混合内容问题:当一个安全的 HTTPS 页面试图加载非安全的 HTTP 内容时,这种情况被称为"混合内容"。浏览器通常会阻止这种行为,因为它降低了整个页面的安全性。
  2. 安全风险:HTTP 内容没有加密,易受中间人攻击。如果在 HTTPS 页面中加载 HTTP 内容,攻击者可能利用这个未加密的内容来攻击整个页面,比如通过注入恶意脚本。
  3. 隐私和完整性:HTTPS 旨在保护用户数据的隐私和完整性。混合内容使得 HTTPS 页面的这些保障部分失效,因为嵌入的 HTTP 内容不受同样的保护。
  4. 用户信任:用户可能信任一个安全的 HTTPS 页面,如果这个页面包含不安全的内容,这可能误导用户,使他们对整个页面的安全性有错误的理解。

调转方向,研究第二个思路。其实,此时问题可以进一步细化:任意给定一个 http 的链接,如何用 https 来访问?

自然而然,面对和 url 相关的需求,首先想到的就是 nginx 代理(什么,想不到?!那就多看看烂笔头的文章:》)。大概思路如下:

  1. 搭建一个 nginx 代理服务;
  2. 提供一个基于 https 的 url,nginx 接收到请求 url;
  3. 编写 lua 脚本,实现对请求 url 解析,生成原始的 http 请求 url;
  4. 使用 proxy_pass 将 https 的请求转发给 原始的 http 地址。

需要注意的是,这种方案需要有个前置条件,具备泛域名证书。泛域名证书要钱?来看看这篇文章,申请一个免费的~《网站要上 HTTPS 却没有 SSL/TLS 证书?| 教你一招搞定免费的(泛域名)SSL/TLS 证书》

2 | 实战

2.1 转换规则

要实现https url 转 http url,首先需要设置转换规则。我们知道,url 是由 协议+域名+端口 组成的,比如:

可以看到,一个 url 里会包含字母、数字、符号等等,那么可以设置转换规则如下:

  1. 数字/字母 -> 数字/字母
  2. 符号 -> {符号英文} ,比如 . -> _dot_, : -> _colon_
  3. 真实 url 转换后的字符串作为 base url 的二级子域名

假设 base url 为 abc.com,那么 http://192.168.0.1:6443 这个 http url 就可以转换为: 192_dot_168_dot_0_dot_1_colon_6443.abc.com

2.2 nginx 关键配置

首先,通过ngx.re.match找出二级子域名,

然后,将值赋给ngx.var.service,

接着,执行proxy方法,在proxy方法里,使用lua的string.gsub函数对字符串做替换操作,生成真实的访问url,

最后,利用proxy_pass 将请求转发出去。

这里展示核心代码:

ini 复制代码
server {
    listen 80;

    location / {
      set $service  '';
      set $type '';
      rewrite_by_lua '
        local host = ngx.var.host
        local m = ngx.re.match(host, "(.+).abc.com")
        ngx.var.service = m[1]
        ngx.exec("@proxy")
      ';
    }

    location @proxy {
      access_by_lua_block {
        local req_service = ngx.var.service
        local real_service = string.gsub(req_service, "_dot_", ".")
        real_service = string.gsub(real_service, "_slash_", "/")
        real_service = string.gsub(real_service, "_colon_", ":")
        ngx.var.service = real_service
      }
      proxy_pass http://$service;
    }
}

需要注意的是,这里只是最核心的部分代码,还有一些必要的nginx配置(比如加头,支持ws协议等等),需要根据业务需求定制化去增加和修改。

以上。

相关推荐
万物智能1 小时前
SARADC模数转换—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
前端·后端
花间相见1 小时前
【后端开发|网络编程】—— 五种实时通信方案全解析:短轮询、长轮询、SSE、MQTT、WebSocket
后端·网络协议
坤岭1 小时前
LLM应用安全护栏实战
后端
程序猿阿越1 小时前
containerd如何创建Pod
后端·kubernetes·源码阅读
名字还没想好☜1 小时前
Python sqlite3 实战:事务提交、参数化防注入、WAL 并发与 row_factory 取字典
后端·python·编程语言
花间相见1 小时前
【AI应用开发|Agent记忆】—— Codex 与 Claude Code 持久化记忆对比:两条不用向量库的路线
后端·agent
葡萄城技术团队1 小时前
GcExcel V9.2 新特性揭秘:公式对象的无损往返
后端
蜗牛互联网1 小时前
Claude放宽生命科学限制:代价是验证、分级和30天留存
java·人工智能·后端
Linux运维技术栈1 小时前
如何避免绕过CDN的攻击?基于 CDN 回源请求头鉴权的防御实操与安全性剖析
nginx·安全·cdn
上进小菜猪1 小时前
被 32 位整数卡了 30 年脖子:PostgreSQL 事务号困局与 V9 的 64 位解法
后端