我把所有私有图片全部加密存储了,因为我不相信国内所有云厂商的职业操守

陪她去流浪 开发笔记 阅读次数:391

前段时间刚把《腾讯云:都是你自己的错,我哪里有错》这篇文章写完的时候,推特上面也迎来了另外一波对腾讯云的讨伐,很是精彩。

其中关于 “为什么数据被腾讯云明确表示‘彻底’删除后,因为舆论反响太大的原因,又被恢复了。”, 我在评论区看到一些评论提到一些观点(原文没找到了,我回忆):

  1. 出于国内政策需要,理论上,所有数据都不会删除,以防后期追溯/审查;
  2. 它们完全有能力轻易地查看客户的所有数据。

我没有很意外,甚至完全在我理解的“情理之中”。

所以这么多年来,就算我博客图片加载速度再慢,我也一直使用自己的服务器资源, 不会为了加快访问速度而把资源交给国内的云厂商。 因为我完全不想因为哪天它们奇怪的政策不提前告知我而把我的数据删掉。

当然,我更害怕它们能够随意/有权限随意查看我的私人数据。 从上面文章的内容也能看到,他们一再要求我提供我自己生产环境私钥,这对我来说,我觉得这是一件极其离谱、荒谬的事情。 当然,你可以说我的数据没有任何价值,但对不起,我就是不想给你看。

事情发生了一些反转

近来,由于给博客加上了实况照片1的原因,网站突然出现了不少视频内容,并且需要分享给国内的好朋友。 由于服务器在国外的原因,加载如此大量的视频内容明显会很慢,所以我在月初的时候就已经着手考虑如何提高访问速度事宜。

考虑的结果不出意外的简单:丢云存储/放CDN即可。

但是我又不可能放心地认为数据直接给它们是安全的,所以我必须加密存储。(当然,你会说:更好的建议是不把类似资源存储到任何地方,I do agree.)

如何加密存储图片/视频还能正确加载?

早年研究 Fabrice Bellard 实现的 BGP2 图片格式时,了解过他是如何在浏览器中实现自定义解码器的:他监听了所有图片的 onerror 事件,并在处理的时候判断是不是 .bgp 图片格式。 如果是,则自己重新解析图片,并绘制到 <canvas>

我自己现在的做法其实也很简单(针对私有文章的图片或视频):

  1. 服务端后台同步线程会用 AES-256-GCM 加密算法加密图片后再上传到云厂商的对象存储
    1. 服务器端加密:密钥初始化向量/随机数完全随机自动生成,并存放在服务端(不会与云厂商共享);
    2. 上传到云厂商:路径形如:objects/d41d8cd98f00b204e9800998ecf8427e,后半截是文件哈希;
  2. 前端文章中的 URL 仍然不变,但是请求的时候不会返回真实的图片内容,而是返回“一些参数”。其中包含:
    1. 预签名✍️的私有云厂商访问链接(因为存储桶是私有的);
    2. 加密时用到的密钥
    3. 加密时用到的初始化向量/随机数
  3. 这不是正确的图片,会 onerror,然后就在浏览器端用 WebCrypto API 解密加密访问链接对应的文件3
  4. 解析出来后,用 URL.createObjectURL() 将其创建为 Blob 对象 URL,重新设置到 img.src 上显示;

整个过程其实非常简单,唯一我觉得稍微有点影响的是:图片显示速度会慢一丢丢。

然而,为了安全而牺牲的这一点点性能,我完全可以接受。

并且,这一切的一切操作,对于前端/用户/文章编辑来说,都是完全透明的,没有任何操作上的不同。