当我谈博客安全时,我在谈些什么

网站

我这个人是那种万事皆以安全为首任的性情,表现得准确一点,是那种危险不大仍裹足不前的性情。站在斑马线上,不但看正常来车方向,也会观察逆行车辆。一边走,一边左顾右盼,生怕盲点窜出个骑着电驴的外卖员。与其相信道路使用者遵守交通,不如相信自己。

博客读者不多,留存、阅读量指标少得可怜。使用 Google Analytics 查看数据,期待地打开,失望离开。当然,一切责任都在于没有稳定更新博客的我。虽然访客少得可怜,他们的网络安全也是安全。会否有人受害是一回事,避免访客暴露于危险中才是我关心的。

建站之初,有意选用兼顾易用和安全的方案——Cloudflare 搭配 Netlify 加上 Hexo。对本站的安全、性能,我十分自信

  • 100% 静态网站,使用 Hexo 生成原生 Markdown
  • Netlify 提供托管、HTTPS
  • Cloudflare 负责 CDN
  • 不用 Wordpress 或 CMS
  • 没有表格,访客无法输入

Cloudflare 为什么要配合 Netlify 使用?和练习吉他的思路很类似。连续几天左手按弦演奏,连续几天光右手拨弦训练持久力……单调且无趣的噪音。然而当它们结合,美妙旋律显现。

它们就像你的左右手。Netlify 用来托管不错,可惜限流,CDN 和安全设定也较为稚嫩。Cloudflare 提供的专业 CDN 服务作为互补完美不过。

每年十月是欧盟、美国的网络安全意识月,抓住今年安全月的尾巴,对博客进行安全检查。不查不知道,一查吓一跳!之前以为是坚实的金属堡垒,实则是底部穿了小孔的残破锅子,表面还带点锈迹。

image-20211029231211678

我使用多个工具进行综合评估。 Security Headers 负责博客 headers,Qualys 检查加密、Internet.nl 给出全面安全评价。

Internet.nl 警告我未开启 DNSSEC 以及博客使用不安全 TLS 版本连接。Security Headers 则在报告中显示我没有任何 security headers。

今天的目标是把他们根除。

在 Cloudflare 打开 DNSSEC 和 HSTS

Cloudflare 有一篇中文博客 图文并茂地讲述了 DNSSEC 的原理

DNSSEC 在原本不安全的协议之上启用经过身份验证的答案,因此增加了一个安全层。DNSSEC 对响应进行签名,从而检测伪造响应。

简单来说,启用 DNSSEC 降低 DNS 劫持风险。Cloudflare 提供一键打开 DNSSEC 的功能。

image-20211030001358866

启用后,还需要到域名注册商(我是腾讯云)添加 DS 记录。腾讯云所使用的术语和 Cloudflare 相差很大,按照 教程对应 Cloudflare 提供的 Key Tag、Algorithm、Digest Type、Digest ,填写 关键标签加密算法摘要类型摘要

我搞定 DNSSEC 后,在 Cloudflare 里 SSL / TLS 分类中,打开「始终使用 HTTPS」,把最低 TLS 版本设为 TLS 1.2 ,启用 TLS 1.3,支持自动 HTTPS 重写。

TLS Cloudflare.002

HSTS (HTTP Strict Transport Security)

自动 HTTPS 重写会把 HTTP 重定向到 HTTPS,仍有必要使用 HSTS 防范中间人攻击。按照 HTTPS 的协议,第一次连接服务器的请求,仍然是 HTTP,之后才会变成 HTTPS。攻击者以此尝试盗取 cookie 数据。打开 HSTS 后,即使第一次请求,也会是 HTTPS,有效杜绝这类攻击。

启用 HSTS 后,访客无法使用 HTTP 连接。我要保证网站的 HTTPS 配置正确,不然要直到 max-age 周期结束才会恢复正常(以年为单位的周期)。按照 Google 对 Strict-Transport-Security 的建议,分阶段设置 max-age,第一次是 5 分钟,然后是一周、一个月,都没问题后,才设置到一年。

During each stage, check for broken pages and monitor your site’s metrics (e.g. traffic, revenue). Fix any problems that come up and then wait the full max-age of the stage before you move on. For example, wait a month in the last stage.

如果你的网站对你是吃饭的工具,请勿立刻上马,应分阶段测试。这里我就不管那么多了。首先,我到 Cloudflare 把 HSTS 启用,max-age 至少要设置 31536000 秒(约一年)。

image-20211030114354792

Netlify 提供 两种方法 设定自定义头,分别是 _headers 文件和 Netlify 配置文件 config.toml 。本文使用后者。

开启我的 config.toml ,添加 headers 值,31536000 是以秒为单位的一年,includeSubDomains 包含子域名,preload 则是提交到 Google HSTS Preload List 的强性要求。

[[headers]]
  for = "/*"
  [headers.values]
	Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"

使用 Qualys - SSL Lab 检查,HSTS 启用成功。

image-20211030114546103

接下来要把网站提交到 Google HSTS 预加载名单。名单由 Google 维护,并且放到浏览器的源代码中。浏览器首次连接网站前,查看网站有否出现在名单上,保证第一次请求也有 HTTPS 加密保护。市面主流浏览器,包括 Safari、Firefox、Edge、Opera,皆使用这个名单。提交后等一两个月是常事,浏览器推出更新这个名单才会刷新。

image-20211030115236561

✅ 再次对博客进行安全检查,分数达到 A+!浏览网站不同页面,无异常。

image-20211030111956630

Netlify 配置文件添加 Security Headers

image-20211030122254654

首先,我到 Cloudflare HSTS 的设定里打开无嗅探标头,自动添加 X-Content-Type-Options: nosniff

image-20211030122151806

接下来还有 Content-Security-Policy(CSP)、X-Frame-OptionsReferrer-PolicyPermissions-Policy 要设置。Jiansing 发布的关于 部署 Netlify security headers 文章 讲得通俗易懂,涉及原理和配置代码例子,对我帮助颇大。CSP 启用后,颇多服务失效,需要添加域白名单。不同网站状态需具体分析,还有待调试出最适合我的配置。

X-Frame-Options = "SAMEORIGIN"
Referrer-Policy = "no-referrer-when-downgrade"
Permissions-Policy = "accelerometer=(); ambient-light-sensor=(); camera=(); gyroscope=(); magnetometer=(); microphone=(); payment=(); usb=()"
X-XSS-Protection = "1; mode=block"

再次进行 Security Headers 测试,前后差别不可谓不大。

ssl compare 2.001

后记

我多次尝试 HSTS、DNSSEC,读完网上教程止步,已有五六次了吧。这些网络安全的名词如同天书一般,原理、设置、用途,每一个环节都需要专业知识和耐心。想不到这次发起冲锋,阅读资料却无以往一般艰涩。一次又一次的尝试,接着放弃。积累失败的经验,不等于失败。或许正是之前那些看似无效的阅读,为我打下一定的知识基础(即使在很多人看来是薄弱的)。

这是一个愚蠢的年代,也是一个智慧的年代。互联网带来了推荐算法、短视频肆意掠夺注意力,同时,知识以前所未有的方式自由流动,思想得到碰撞。其中大部分功劳,属于网络上的技术博客。感谢他们无偿发布高质量文章,在没有收入奖励下用爱发电,不分贵贱、地域,培育技术发展的土壤。

参考