使用Let's Encrypt给网站添加HTTPS证书
引子
聊天、刷网页、使用app的时候,输入账号、密码登录是很常见的事。 那么这些信息会被除了你和服务端的第三方知道吗? HTTP协议传输确实是明文的,意味着数据传输的每个环节都可以看到其中的内容,像是寄送一张明信片。
聪明如你肯定知道传输过程可以加密,这样即使传输过程中包含敏感信息也不会被轻易的破解,只有发送、接收双方知道内容是什么。 HTTPS就是加密版本的HTTP,AI跟我说HTTPS除了目标地址和端口号,其余内容都是加密的。
聪明如你肯定也知道,加密有对称加密和非对称加密。 加密和解密都需要一个数字版的钥匙,对称加密是指的加密和解密使用的钥匙是一样的,而非对称加密有一个公钥和一个私钥。
非对称加密可以使用公钥对信息进行加密然后用私钥进行解密,也可以使用私钥对信息加密然后由公钥解密。 公钥、私钥只是一个相对的概念,可以告诉外界的是公钥、自己保留的是私钥。 公钥可以告诉外界,是因为知道公钥并不能(轻易地)推导出私钥,而用公钥加密的数据只能由对应的私钥解开(或者用私钥加密的数据只能由对应的公钥解开)。
使用公钥加密数据的场景就是常见的客户端与服务器通信过程,服务器将公钥告诉用户,用户将自己的数据使用公钥加密, 除了服务端没有其他人知道私钥,用户的数据只有服务端能够解密。 使用私钥“加密”数据的场景有,拥有者公布自己的公钥和身份,然后将某些文件用自己的私钥加密, 收到加密数据的大众可以使用公钥尝试去解密,解密成功则证明该文件确实来自拥有者,这种情况用于数据“签名”。
顺便提一下,除了网页应用,邮箱也有加密和签名的功能,道理同上。 但是这就要求发送方知道接收方的公钥(加密场景),或者接收方知道发送方的公钥(签名场景), 否则接收方收到的只是无法解密的数据。
回到正题,所以在浏览网页的时候,(简化来说)用户使用网站提供的公钥,将请求加密,就只有服务端能够用它的私钥解密,进而提供后续的服务。 传输的过程就是安全的……吗?
以上我们假设通信双方都是正确的人,用户知道这个公钥的拥有者就是真正的服务提供商。 那么如果出现了第三者呢?
假设A需要和B通信,出现了第三个人C,C冒充自己是B并向A提供了C的公钥。 A用C提供的公钥对信息进行加密发给了C,C在接收到的信息的时候用自己的私钥进行了解密, 然后C假装自己是A将信息再用B的公钥加密发送给B。 B以为自己收到的是来自A的信息,进行处理后返回给了C,C再将收到的消息发回给A。 这样A、B双方并未察觉到中间人C的存在。 即使实际上AC之间与CB之间的通信都是加密的,C也已经窃取到了AB之间的秘密。
所以要如何让A知道,他所收到的公钥确实是来自B的呢?
HTTPS证书
假设你有一个域名 example.com ,以及一个云服务器(比如ECS)。 现代的云服务器应该多是基于容器的独立空间,就像一个远程的完整操作系统一样。
你可以使用Nginx作为HTTP服务器为用户提供内容。 若要开启HTTPS,在服务器上自己生成一个公私密钥对也是可以的,只是通常浏览器会提示你这个网站有风险,因为它不能证明自己的身份。
(为什么不能信任对方身份呢?这就有一点(只有一点点)类似于:诈骗电话可以使用伪基站将来电显示名称修改成某些公共服务电话一样)
防止前面提到的中间人攻击的方案就是引入证书机制(Certificate)。 简单可以理解为一个“权威”机构或者其子机构提供数字证书证明 example.com 确实拥有某个公钥。 当然证书颁发机构以及证书本身也需要数字签名来确保内容不是被篡改过的。
在操作系统或浏览器中,已经预置了许多根证书,根证书可以为子证书认证。 一整套的认证链可以确保在数据加密前,我们使用的公钥确实是来自目标服务(如银行、电商、社交网络等)。
所以现在,你需要的,就是将自己的域名和公钥提供给认证机构,让他们给你一个证书。 在用户与你的服务器建立连接时,你会将自己的公钥和证书传输给用户,用户(的浏览器)校验过后才开始建立数据传输。
获取证书
那么现在的问题是,如何获得一个证书呢? 希望云服务提供商为你的域名和服务提供证书?只有一个字,交钱、交钱、交钱!
我们不可能把自己的信息生成一个证书装遍世界的每台设备上。 设备(浏览器)普遍安装了某些根证书,子机构可以从上一级那获得认证,一层又一层, 最后我们交钱、填表让某个末端认证机构把我们的公钥认证了。
不想交钱把活干了,可以吗?
可以的,Let's Encrypt就是这么一个方案。 Let's Encrypt 是一个免费、自动化且开放的 证书颁发机构(CA)。
(以下来自AI)
- 完全免费: 任何人都可以为自己的域名申请有效的 SSL/TLS 证书,不收一分钱。
- 自动化: 配合名为 ACME 的协议,程序可以自动完成申请、验证、下载和配置。
- 自动续期: 它的证书有效期只有 90 天。虽然看起来很短,但其目的是强制用户使用自动化工具。在到期前,服务器上的脚本(如 Certbot)会自动续期,你甚至感觉不到它的存在。
- 安全透明: 所有的证书颁发记录都是公开可查的,且遵循最新的安全标准。
具体操作
在Let's Encrypt官网(2026年01月的当下), 其推荐使用Certbot ACME客户端。
自动签发证书的原理是(以下来自AI):
- 证明所有权: 你在服务器上运行一个客户端软件(如 Certbot)。它会与 Let's Encrypt 通信。Let's Encrypt 会给出一个“挑战”,比如要求你在网站特定路径下放一个文件,或者修改一个 DNS 记录。
- 验证成功: 一旦 Let's Encrypt 检查到该文件或记录,就证明你确实拥有这个网站。
- 颁发证书: 验证通过后,Let's Encrypt 会立即签发证书并传回给你的服务器。
在Certbot网页上选择使用的服务端程序以及操作系统,便会列出具体的操作步骤。 因为我使用在Linux系统上的Nginx,加上比较熟悉Python,就选择了Nginx+Linux(pip)。
大致步骤是:
- 安装必要的运行依赖,如 Python、venv、pip
- 创建一个Python的虚拟环境,如此 Certbot 的相关工具只运行于这个独立空间中
- 使用 pip 安装 Certbot 并且执行命令自动开始签发流程
- 最后设置了一个定时任务,自动运行程序进行证书更新
在开始之前,在Nginx的配置文件中配置好各个域名(及子域名)的HTTP处理方案。 Certbot程序运行后,其会读取这些信息并自动加上HTTPS的方案,就都完成了。 如果有所遗漏,修改完HTTP部分的信息再重新运行一遍Certbot程序即可。
对了,如果你完成这些操作却无法进入你的HTTPS链接,有可能是云服务商防火墙默认没有打开443端口(HTTPS默认端口),找找看开启它。
尾声
实际上我的网站是静态的,没有账号密码系统,使用HTTP协议就够了。 但是现代的浏览器输入域名可能会自动跳转到HTTPS的链接,或者在指定HTTP连接的时候用个红叉来提示用户连接不安全。 所以为了消除这种会让用户产生不安心理的情况,我还是得开启HTTPS。
当然浏览器的这些功能是没有错的,在访问网站的时候如果出现安全风险提示,也还是要警惕。
最后,还是要注意,证书系统只验证“你是否真的拥有这个域名”,并不验证“这个域名是否真的是用户所需要的”。
例如 163.com 被认证了,并不能阻止 l63.com (L)也可以获得一个合理的证书,
好似“康师傅”这个商标不能阻止“康帅傅”商标的存在。
浏览器中有HTTPS证书认证的小锁,并不意味着对方一定就是你要找的服务方。