记一次生产报错的曲折解决,HTTPS页面iframe嵌入HTTP协议ES页面混合资源问题

2,163 阅读5分钟

背景

  • 所在部门22年Q4季度开发了个新系统,我负责前端部分的开发,系统中需要开发一个基于ES的图形界面,考虑到开发周期和难度,和leader确认了一下决定使用iframe嵌入现成的ES kabana的页面
  • 开发测试阶段都没遇到什么大问题,就上测试环境时kibana嵌入的页面需要登录认证,用Nginx代理时给相应请求头里携带kibanaAuthorization也很快解决了,leader见测试没问题了,在年后我没回公司的时候(实习生,元旦前阳了请假回家了,年后又请了半个月假)对项目进行了上线,发现页面出不来

问题分析

问题

  • 二月中旬回到公司看了一下控制台报错:
Mixed Content: The page at 'https://' was loaded over HTTPS, but requested an insecure frame 'http://'. This request has been blocked; the content must be served over HTTPS.
  • 报错很明确HTTPS界面引入HTTP资源,混合资源,浏览器阻止了载入混合内容
    • 看到这报错瞬间明白了,我待的部门内部的系统就现在开发的这个搞特殊用的HTTPS,其他的系统包括该系统的测试环境都是HTTP

搜罗的解决方法

  • 问题明确了那解决方法也明确了,毕竟有这么经典的一句话“你碰到过的问题总有前人也碰到过搜索引擎会给你答案”,翻阅内部wiki加上搜索引擎给的答案总结出了三个方法:
  1. kibana的协议升级成HTTPS
  2. 将开发中的系统生产环境协议降级为HTTP
  3. 通过nginx代理,代码中更改嵌入页面协议为HTTPS,通过nginx代理该链接请求HTTP的链接
  • 从上面的方案来看第一条无疑是最好的,折腾少风险低,还都升级为更安全的HTTPS,多好,从网上搜罗的信息发现公司已跳槽的老前辈屈光宇大佬的博客里也推荐使用这种,遂信心满满将方案告知leader,然后前面两条很干脆的被否决掉了……

障碍

  • leader给出的解释总结下意思大概如下:

    • kibana部署的机器是中台的,那儿不好协调,改这个想都别想,第一个方案卒
    • 现有平台已存在一段时间更改协议有风险,不知道会不会影响到其他系统,就已知引用了该系统的咱自己部门就有一个,第二条方案卒
  • 现存方案仅剩走nginx代理……

nginx 代理的一些问题

  • leader否决掉前两个方案之后就只能走nginx代理了,也幸亏这方法也不难办,反向代理一下kinaba的该域名就行,可就是这看似简单的一个代理把我和mentor给难住了,不管怎么写,代理最后都会走到开发中这个系统的域名上去!
    • 这个系统原有的nginx配置的太“霸道”了,只要是走这个机器的请求,没有域名的统统会被代理到该系统的域名下,kibana的地址还是裸的协议+ip+端口,而且这个配置问了mentor还不敢随意动,不知道哪个犄角旮旯里的代码请求就会走这个……
    • 试过了过滤忽略掉kibana的地址代理,但是依旧解决不了
    • 试过嵌入的页面写开发中系统的域名,代理该链接的params也解决不了,嵌入的kibana页面请求太多了,params前缀还不一样,不可能全给写上,漏掉一个都会跳到现有系统……

最终方案

  • 多次尝试无果之后,无意中发现该系统域名申请的ssl证书为
    ssl_certificate     /search/code/nginx/ssl/_.xxx.xxx.xxx_bundle.crt;
    ssl_certificate_key /search/code/nginx/ssl/_.xxx.xxx.xxx.key;
  • xxx.xxx.xxx为公司二级域名),也就是说只要申请的三级域名符合以这个二级域名结尾就可以共享这个证书!而询问过后发现再申请一个三级域名就只需要提交个申请就可以,只要符合规则,审核的是自己人!
  • 申请的域名很快就下来了,该域名也解析到我们项目部署的机器ip,有了域名那就好办多了
  1. 另起一个nginx的配置文件
    • 该配置文件不管他什么请求,只要走这个域名的我们统统给他代理到kibana的部署地址上去
server {
    listen       443 ssl;
    # 申请的域名
    server_name  kibana.xxx.xxx.xxx;
    ssl_certificate     /search/code/nginx/ssl/_.xxx.xxx.xxx_bundle.crt;
    ssl_certificate_key /search/code/nginx/ssl/_.xxx.xxx.xxx.key;

    location ~ .*(.htm|.html|manifest.json)$ {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }

    location / {
         # kibana 部署地址
         proxy_pass  http://xxx.xxx.xxx.xxx:xxxx;
         # 跳过kibana登录认证
         proxy_set_header  Authorization "Basic 账号密码生成的base64编码后数据";
    }

}
  1. 将嵌入的iframe链接的origin部分改为我们现在刚申请的这个域名

问题解决

后记

虽然是个很小的问题,但是解决的过程却十分艰难,本来只要大家配合几下子就解决的问题却卡了我三天,最终还是通过曲线救国的方式解决掉的,后期项目开发换人了维护的成本也远比直接将kibana协议升级来的高,职场有时候真不是理论上的最佳方案就是最佳,结合实际的各方阻碍,最终的解决可能在我们最初看来真的不那么完美。