Horo
Horo

目前是 LikeCoin Chain 验证人 Yoitsu 背后的家伙,以及 CDC/CFC 划水组成员(笑)。偶尔会变身成狐狸。( @foobarz )

如何比较安全的配置 Web 服务器之一 - TLS 和 HTTPS

1202 年了,还是有不少网站没有上 HTTPS 的。

又是一次知道的已经做好了,不知道的对着他耳朵唠叨也不会去做的系列节目。(嗯?) 如果不想听咱啰嗦的话, 直接去看 Mozilla Infosec 的相同主题的内容就好啦。

HTTPS 和 TLS 到底是什么关系?

HTTPS 其实就是包在 SSL/TLS 里的 HTTP 啦,考虑到 SSL 3.0 早在 2015 年就废弃了,现在基本上就只提 TLS 了。(虽然 TLS 1.0 和 1.1 也在 2020 年被废弃了就是。)

因为 HTTPS 能够加密所交换的数据、在传输的过程中保证数据的完整性,以及证明用户是在与目标网站进行通信。所以很多组织都在呼吁让整个互联网的流量都是加密的。 以及各大浏览器也在逐渐的将只支持 HTTP 的网站列入“不安全”的范围。(虽然也有人对这么做有没有作用存疑。)

取得一份证书

关于 TLS 的实现原理不是咱的重点(其实是咱也不是很懂,汝也许可以看看 IETF 的 RFC, 如果真的有必要的话。 汝现在需要知道的最重要的一点就是,要使用 HTTPS 的话,网站管理员要先从大家都信任的某些地方(就是 CA/数字证书认证机构 啦)取得一份带有私钥的证书才能继续接下来的步骤。

有不止一家企业和组织营运的 CA 负责签发证书,例如历史悠久的 Entrust 和 DigiCert ,和数个公司或组织为了普及 HTTPS 创办的 Let's Encrypt 等等。

如果汝还没有预算购买证书的话,可以先从 Let's Encrypt 开始

不过 Let's Encrypt 的证书有效期只有三个月,所以如果汝对自己的服务没有完整的命令行访问权限(例如比较常见的虚拟共享主机)的话,可能会稍微麻烦一些。
至于怎么申请证书嘛, Let's Encrypt 推荐使用它们制作的 certbot 帮助程序。 可以在这里查阅文档, 咱就先跳过了(笑)

如果希望只允许特定的 CA 给汝的网站签发证书的话,可以通过 DNS 证书颁发机构授 权记录(简称 CAA)来实现,CA 会提供相应的指南告诉汝如何添加和修改这种记录。

规划网站的兼容目标

越新的标准越能提升安全性,越旧的浏览器就越有可能不支持,大概就是这个样子。所以根据自己网站的受众决定向后兼容的程度就很重要。Mozilla 的标准有三个等级:

  • 现代等级:只支持 TLS 1.3,适用于不需要向后兼容的新网站。
  • 中等等级:支持 TLS 1.2 和 1.3,适用于大多数网站和估计近五年间的设备。
  • 向后兼容等级:只有汝需要考虑支持像是 Windows XP 或者 Java 6 这种相当老的系统时才应该使用这个等级。

Mozilla 也提供一个线上配置生成器,可以根据不同的等级和服务器软件生成合适的参考配置文件。 根据汝的需要稍加修改(例如证书的位置)应该就可以使用了。

正确的重定向 HTTP 链接

现在汝的网站有 HTTPS 版本了,很好。但只有用户主动的输入带有 https:// 的地址的时候才能访问 HTTPS 版本, 于是汝还需要让用户通过 HTTP 访问的时候能自动重定向到 HTTPS 版本。

对于目前比较常见的 Apache 和 Nginx 来说,都挺简单的。

# Nginx 示例配置。
server {
  listen 80;
  return 301 https://$host$request_uri;
}

# Apache 的示例配置,记得把 foo.tld 换成汝自己的域名。
<VirtualHost *:80>ServerName foo.tld
  Redirect permanent / https://foo.tld/
</VirtualHost>

HTTP 严格传输安全 (HSTS)

汝设置好了正确的重定向,这本来没有问题,直到攻击者劫持了访问汝的网站第一步的 HTTP 响应…… 一场典型的 SSL 剥离攻击开始了。

所以 IETF 为了补救这个缺陷提出了 HTTP 严格传输安全标准,汝也许经常能看到它的缩写 HSTS 。

要实现 HTTP 严格传输安全,核心就是一个 HTTP 首部,例如下面的这个:

Strict-Transport-Security: max-age=31536000; includeSubDomains

如果 https://example.com 的响应中有这段的话:

  • 在接下来的 31536000 秒(即一年)中,浏览器向 example.com 发送 HTTP 请求时,必须采用 HTTPS 来发起连接。 比如,用户点击超链接或在地址栏输入 http://example.com/ ,浏览器应当自动将 http 转写成 https, 然后直接向 https://example.com/ 发送请求。
  • 在接下来的一年中,如果 example.com 服务器发送的TLS证书无效,用户不能忽略浏览器警告继续访问网站。
  • 这也适用于 example.com 下面的子域名,例如 www.example.com 。

以及这段只有在 HTTPS 响应中才会生效,那汝应该也会想那么第一次访问网站时怎么办。 各大浏览器的做法是维护一个预先加载列表,在列表上的网站总是会通过 HTTPS 访问。 汝可以参考这个网站来了解将自己的网站加入预先加载列表的要求。

OCSP 装订

汝也许听说过一个叫 OCSP(在线证书状态协议)的东西。浏览器每次连接支持 OCSP 的网站时,都会向 CA 发送请求查询这个证书的状态。 但这就带来了两个问题:

  • OCSP 是明文发送的,汝和 CA 之间的任何人都能知道汝在访问哪个网站,虽然不能精确到 URL,但进行阻断的话已经足够了。
  • 如果 CA 提供 OCSP 查询的服务器偷偷的留下了访问的记录……

而 OCSP 装订则改为了服务器向 CA 获取 OCSP 响应并缓存一段时间,用户访问时只要验证从服务器发送来的 OCSP 响应的有效性即可。

# Nginx 示例配置。
server {
    ... 
    # OCSP staplingssl_stapling on;
    ssl_stapling_verify on;

    # 如果汝的 CA 没有提供 OCSP 使用的证书(例如 Let's Encrypt 就没有),
    # 那么不需要设置 ssl_trusted_certificate 属性。   
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;

    # 设置成汝服务器使用的 DNS 服务器。
    resolver 127.0.0.1;
}
# Apache 的示例配置。
# OCSP 装订缓存的位置,
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
<VirtualHost *:443>
...
# 如果汝的 CA 没有提供 OCSP 使用的证书(例如 Let's Encrypt 就没有),
# 那么不需要设置 SSLCertificateChainFile 属性。
SSLCertificateChainFile /path/to/DigiCertCA.crt

SSLUseStapling on
</VirtualHost>

Referrer 策略

Referrer 经常用来表示用户是从哪里来的,也有人担心它会泄露一些隐私信息。 Referrer-Policy 首部用来监管哪些访问来源信息——会在 Referer 中发送——应该被包含在生成的请求当中。

汝可以根据汝的网站和用户选择适合的模式。

# no-referrer-when-downgrade 是现代浏览器的默认设置,
# 在同等安全级别的情况下,引用页面的地址会被发送(HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP)。
Referrer-Policy: no-referrer-when-downgrade
# 只有原地址相同时才发送 Referrer。
Referrer-Policy: same-origin
# 对于同源的请求,会发送完整的URL作为引用地址;
# 在同等安全级别的情况下,发送文件的源作为引用地址(HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。
Referrer-Policy: strict-origin-when-cross-origin
# 对不支持 strict-origin-when-cross-origin 的浏览器不发送首部。
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
# 或者直接什么时候都不发送首部。
Referrer-Policy: no-referrer

X-Content-Type-Options 、 X-Frame-Options 和 X-XSS-Protection

X-Content-Type-Options 用来被服务器用来提示客户端一定要遵循在 Content-Type 首部中对 MIME 类型 的设定, 而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为。

# 防止浏览器不正确的识别文件类型,例如把非脚本文件识别成脚本。
X-Content-Type-Options: nosniff

The X-Frame-Options HTTP 响应头是用来给浏览器指示一个页面可否在框架中展现的标记。 (其实还有 <frame><embed> 和 <object> 的,但这些好像都被弃用了来着。)

站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免被用来进行汝点击的不是实际的地方的那种 clickjacking 攻击。 除了 HTTP 首部以外,内容安全策略(CSP)里的 frame-ancestors 属性也能控制这种行为,但是那个好复杂啊……

# 阻止网页嵌入在框架中。
# 第一行是通过 CSP 设置,第二行是传统的 HTTP 首部形式,它们的效果是相同的。
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
# 只允许相同域名的网页嵌入在框架中。
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
# 只允许特定来源的网页嵌入在框架中。
# 
Content-Security-Policy: frame-ancestors https://framer.mozilla.org
X-Frame-Options: DENY

X-XSS-Protection 响应头是 Internet Explorer,Chrome 和 Safari 的一个特性, 当检测到跨站脚本攻击时,浏览器将停止加载页面。

若网站设置了良好的 Content-Security-Policy 来禁用内联 JavaScript ('unsafe-inline'), 现代浏览器不太需要这些保护, 但其仍然可以为尚不支持 CSP 的旧版浏览器的用户提供保护。

# 启用 X-XSS-Protection,如果 mode 为 block 的话,
# 浏览器将在检测到可能的跨站脚本攻击时停止加载而不是清空页面。
X-XSS-Protection: 1; mode=block

至于那个最复杂的 CSP 嘛…… 下次再说了……

更多资源

除了上面提到的 Mozilla 的文档和配置生成器以外:

  • Qualys SSLlab 可以帮汝测试汝的 HTTPS 配置, 也提供了一些可以参考的文档。
  • BadSSL可以测试汝正在使用的浏览器遇到错误的 TLS 设置时的反应。


CC BY-NC-ND 2.0 版权声明

喜欢我的文章吗?
别忘了给点支持与赞赏,让我知道创作的路上有你陪伴。

加载中…

发布评论