理论说再多,不如亲手做一遍。在这一节,我们将用 OpenSSL——一个开源的密码学工具箱——来生成自己的数字证书。你会看到证书的完整生命周期:从私钥生成,到证书签名请求,再到签发证书,最后验证证书内容。做完这一课,你就能理解HTTPS背后那些证书文件到底是什么样子的了。
准备工作:安装OpenSSL
OpenSSL几乎预装在所有的Linux和macOS系统上,Windows用户可以从 OpenSSL官网 下载安装包,或者使用Windows Subsystem for Linux (WSL)。打开终端,输入以下命令检查是否已安装:
openssl version |
如果显示版本号(如 OpenSSL 1.1.1f 31 Mar 2020),就表示已经安装好了。如果没有,请先安装(Linux使用apt或yum,macOS使用brew)。
第一步:生成私钥
证书的核心是公钥和私钥。我们先生成一个2048位的RSA私钥。执行:
openssl genrsa -out private.key 2048 |
这个命令会生成一个名为private.key的文件,内容是以PEM格式编码的私钥。你可以用文本编辑器打开它,会看到类似这样的内容:
-----BEGIN PRIVATE KEY----- |
注意:私钥必须严格保密,绝不能泄露给任何人。在生产环境中,私钥的权限通常设置为600(只有所有者可读)。
第二步:生成证书签名请求(CSR)
接下来,我们需要向证书颁发机构(CA)申请一张证书,这个申请文件就是证书签名请求(Certificate Signing Request, CSR)。CSR里包含了我们的公钥和一些身份信息(比如域名、组织名称等)。执行:
openssl req -new -key private.key -out request.csr |
系统会交互式地询问一些信息,如:
- Country Name (2 letter code) [AU]:
CN(国家代码) - State or Province Name (full name) [Some-State]:
Beijing(省份) - Locality Name (eg, city) []:
Beijing(城市) - Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Example Inc(组织名) - Organizational Unit Name (eg, section) []:
IT(部门) - Common Name (eg, your name or your server’s hostname) []:
www.example.com(域名,关键!) - Email Address []:
admin@example.com(邮箱)
你可能会被问额外选项,比如挑战密码,直接回车跳过即可。
完成后,会生成request.csr文件。你可以用cat request.csr查看内容,它同样是PEM格式,以-----BEGIN CERTIFICATE REQUEST-----开头。
第三步:生成自签名证书(自己当CA)
在实际生产环境中,你会把CSR发给CA,CA签发证书后返回给你。但这里我们模拟CA,用自己的私钥给自己签发一张自签名证书。这样你就不需要找第三方CA,可以用来测试或内部使用。执行:
openssl x509 -req -in request.csr -signkey private.key -out certificate.crt -days 365 |
解释一下参数:
-req:表示输入是CSR。-in request.csr:指定CSR文件。-signkey private.key:用自己的私钥签名(因为是自签名)。-out certificate.crt:输出证书文件。-days 365:证书有效期为365天。
运行后会生成certificate.crt,这就是你的数字证书。查看它:
openssl x509 -in certificate.crt -text -noout |
你会看到证书的详细信息,包括版本、序列号、签名算法、颁发者、有效期、公钥信息等。特别注意颁发者(Issuer)和主体(Subject)是相同的——因为这是自签名证书。
第四步:模拟HTTPS服务器验证
现在我们来模拟一个简单的HTTPS服务器,用这个证书测试一下。
首先,创建一个简单的HTTP服务器配置,比如使用Python的http.server模块,但它不支持HTTPS。我们可以用openssl s_server命令来快速搭建一个测试服务端:
openssl s_server -accept 4433 -cert certificate.crt -key private.key -www |
这个命令会在本地的4433端口启动一个简易的TLS服务器,任何访问都会显示“CONNECTED”信息和客户端信息。在另一个终端中,用curl测试:
curl -k https://localhost:4433 |
-k参数让curl忽略证书验证(因为我们的证书是自签名的,没有第三方CA背书)。你会看到服务器返回的信息。
如果不加-k,curl会报错,提示证书不被信任。这正是浏览器访问自签名网站时的警告。这说明,只有被信任的CA签发的证书才能被大众浏览器自动接受。
第五步:模拟CA签发证书(创建信任链)
为了真正理解信任链,我们来模拟一个根CA,然后用它给刚才的证书签名。换句话说,我们不要自签名,而是用另一个私钥(根CA的私钥)来签名我们的证书。
生成根CA私钥和自签名根证书:
openssl genrsa -out ca.key 2048
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -subj "/CN=My Root CA"用根CA签发我们的证书:
openssl x509 -req -in request.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out certificate_signed.crt -days 365
参数
-CAcreateserial会生成一个序列号文件。
现在,certificate_signed.crt就是由根CA签名过的证书。如果你把根证书ca.crt安装到系统的受信任根证书列表,那么浏览器就会信任certificate_signed.crt。由于我们没有安装,curl仍然会报错,但我们可以用curl --cacert ca.crt来告诉curl信任这个根证书:
curl --cacert ca.crt https://localhost:4433 |
这次就不会报错了,因为curl使用了我们指定的根证书来验证服务器证书。
你学会了什么?
通过这个实验,你应该直观地理解了:
- 私钥是身份的证明,必须保密。
- CSR是向CA申请证书的请求文件。
- 数字证书由CA私钥签名,包含了公钥和身份信息。
- 自签名证书适合测试,但不被公开信任。
- 信任链依赖根证书,它必须预先安装在系统中。
现在,你已经亲自动手走过了一遍数字证书的完整流程。这不仅是理论知识,更是你在未来配置HTTPS、开发安全应用时,随时可以拿来的技能。
动手试试:试着修改证书的域名(Common Name),看看浏览器访问时有什么不同。也可以生成椭圆曲线(ECC)的密钥和证书,对比一下文件大小。
恭喜你,数字证书的大门已经为你打开!