背景
前几天QA同学在进行测试走查,突然给到我一个提了一个issue,反馈说在测试环境中打开页面点击下载文件但是没有下载下来,当时脑袋里第一反应,不可能吧,本地测试的时候是没有问题....等等,难道是那个问题?
问题定位
打开chrome浏览器,打开控制台尝试复现这个问题,果然是没有反应,仔细看了一下控制台的信息,从控制台中找到了提示
具体信息:
Mixed Content: The site at 'xxxx.net/' was loaded over a secure connection, but the file at 'xx.xx.xx.org/obj/xx-xx/a…' was loaded over an insecure connection. This file should be served over HTTPS. This download has been blocked. See blog.chromium.org/2020/02/pro… for more details.
走读一下这段信息,这个的意思是当前的网站(也就是QA同学测试的这个环境)是以一个Https开头的网站,这个会建立起安全的连接,但是我们下载的这个文件是以http开头的,这个是一个不安全的连接,在https网站下加载这个http开头的链接会有Mixed Content的问题
Mixed Content 走读
看一下MDN上面关于这个Mixed content的相关介绍
当用户访问一个通过https serverd出来的页面的时候,这时候和网页之间的连接是基于TLS加密的,所以可以防止大部分的sniffers还有中间人攻击。一个https页面中包含着通过明文http获取内容的话,这个页面就被我们称为「混合内容页面」。像这样只有部分加密的页面只有部分加密,使得sniffers和中间人攻击者可以访问未加密的内容。酱紫页面就不安全了。
Mixed Content分类
- Mixed passive/display content
- Mixed active content
这两种的区别在于,如果内容作为中间人攻击的一部分被重写,最坏情况场景的威胁级别会不一样。在Mixed active content的情况下,威胁较低(页面可能包含误导性内容,或者用户的cookie可能被盗)。在主动内容的情况下,威胁可能导致网络钓鱼、敏感数据泄露、重定向到恶意网站等。Mixed passive/display content 这种不能更改网页的一些内容,一般是通过一些适当的图像之类的,Mixed active content 可以访问HTTPS页面的全部或者部分Document Object Model,除了改变行为还可能窃取敏感数据等,还可以重写响应以包含恶意JavaScript代码,或者让用户重定向到其他HTTP页面并窃取cookie等行文。
Passive content 的类型
<img>
src属性<audio>
src属性<video>
src属性
Active content 的例子
<script>
src属性<link>
href<iframe>
src属性- xhr、fetch 请求
- css 使用url()加载的情况
<object>
data属性Navigator.sendBeacon
url属性
解决方案
按照MDN上面提供的建议,最佳实践是将所有内容都转为https,这里我们就处理一下http的下载资源
原先的代码
const downloadURL = (url: string, filename?: string) => {
const anchor = document.createElement('a');
anchor.href = url;
filename && (anchor.download = filename);
anchor.click();
};
function downloadResource(url: string) {
downloadURL(url);
}
改造之后
const downloadURL = (url: string, filename?: string) => {
const anchor = document.createElement('a');
anchor.href = url;
filename && (anchor.download = filename);
anchor.click();
};
function downloadResource(url: string) {
// 有一些下载url是http开头的,在https的域名下面下载的话会有mix content问题,这里转成https
if (url.startsWith('http:')) {
const replaceUrl = url.replace('http:', 'https:');
downloadURL(replaceUrl);
} else {
downloadURL(url);
}
}
验证结果
测试了一下,没有出现之前那种下载没有反应的情况,改造完成