第4章 OpenSSL工具入门:安装、基本命令、生成自签名证书
说到TLS双向认证,OpenSSL是个绕不开的家伙。这工具我用了十几年,从刚开始手忙脚乱敲命令,到现在闭着眼都能写出一套证书签发脚本。说白了,OpenSSL就是密码学领域的瑞士军刀,什么对称加密、非对称加密、证书签发、随机数生成……它全包了。
我见过不少新手上来就找什么“一键生成证书”的GUI工具,结果出了问题不知道根儿在哪儿。OpenSSL虽然命令行看着有点吓人,但一旦你掌握了这几个核心命令,后面的双向认证配置就会特别通透。
4.1 安装OpenSSL
不同操作系统安装方式不同,但核心版本我建议至少用1.1.1以上。现在大部分系统都默认带OpenSSL,不过版本可能偏老。
| 操作系统 | 安装命令 | 典型路径 |
|---|---|---|
| Ubuntu/Debian | sudo apt install openssl | /usr/bin/openssl |
| CentOS/RHEL | sudo yum install openssl | /usr/bin/openssl |
| macOS (Homebrew) | brew install openssl | /usr/local/opt/openssl/bin/openssl |
| Windows | 下载安装包或使用WSL | C:\Program Files\OpenSSL-Win64\bin\openssl.exe |
我个人习惯在Windows上用WSL里的OpenSSL,省去配置环境变量的麻烦。你如果非要用原生Windows版,记得把bin目录加到PATH里,不然每次都得敲全路径。
装完验证一下:
openssl version
# 输出示例:OpenSSL 1.1.1w 11 Sep 2023
嗯,看到版本号就说明装好了。如果你看到的是1.0.2,我建议你升级,因为1.0.2已经停止安全维护,有已知漏洞。
4.2 基本命令速览
OpenSSL的命令结构是 openssl [子命令] [参数]。我挑了几个最常用的,你可以当成“逃生工具包”记下来:
- 查看帮助:
openssl help或man openssl - 生成RSA私钥:
openssl genrsa -out server.key 2048 - 从私钥提取公钥:
openssl rsa -in server.key -pubout -out server.pub - 查看证书内容:
openssl x509 -in cert.pem -text -noout - 计算文件哈希:
openssl dgst -sha256 myfile.txt
为什么我特别推荐2048位?因为1024位现在已经不安全了,而4096位性能开销大,对于大多数API场景,2048位是性价比最高的选择。我在一个支付项目中就吃过亏——甲方要求必须用4096位,结果握手延迟多了将近一倍,后来改成2048位才过性能压测。
4.3 生成自签名证书
自签名证书说白了就是自己给自己当CA。虽然浏览器会报不安全,但在开发环境、内网接口、或者双向认证测试中,它是最方便的工具。
我习惯于分三步走,清晰不绕弯:
- 生成私钥
- 生成证书签名请求(CSR)
- 用私钥签名CSR得到自签名证书
下面把这套流程拆开看:
步骤1:生成私钥
openssl genrsa -out server.key 2048
chmod 400 server.key # 私钥权限必须严格限制
这条命令生成一个RSA私钥,输出文件是PEM格式。你可以用 openssl rsa -in server.key -text -noout 查看私钥的模数、指数等信息。
注意:私钥文件一旦泄露,你的安全体系就全完了。我在某次渗透测试中碰到一个客户,居然把私钥放在Nginx的静态目录下,直接被爬虫下载了……
步骤2:生成CSR
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=api.example.com"
-subj 这部分直接填就行,省得交互式问答。如果是在双向认证场景,CN 字段很重要——客户端会用它来验证服务端身份。我在一个物联网项目里,就因为CN填了个IP地址,结果客户端证书校验老是失败,折腾了两天才发现是CN和DNS不匹配。
常见的字段含义:
- C:国家代码,CN是中国
- ST:省份
- L:城市
- O:组织名称
- CN:公用名,通常填域名
步骤3:生成自签名证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
这条命令的意思是:用你自己的私钥去签名你自己的CSR,有效期365天。得到的 server.crt 就是自签名证书。你可以用 openssl x509 -in server.crt -text -noout 看看它里面包含了什么——签发者和主题一模一样,这就是自签名的特征。我曾经在调试时发现证书有效期竟然是1970年,一看忘了加 -days 参数,默认只有30天……
实操小技巧:把三步合成一行脚本,以后用起来方便:
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -subj "/C=CN/O=Dev/CN=localhost"
-nodes 表示不加密私钥,省去每次启动服务输密码的麻烦。生产环境不要用这个参数。
4.4 验证证书
证书生成完,你得确认它没问题:
openssl verify -CAfile server.crt server.crt
# 输出:server.crt: OK
对于自签名证书,-CAfile 填它自己就行,因为CA就是自己。如果是CA签发的证书,要用CA证书去验证。
你还可以检查证书的指纹(SHA256):
openssl x509 -in server.crt -fingerprint -sha256 -noout
这个指纹在双向认证里可以用来做指纹校验,我见过一些高安全场景不信任CA链,直接硬编码指纹在客户端代码里。
4.5 常见避坑指南
- 私钥格式问题:有些Java应用需要PKCS8格式的私钥,可以用
openssl pkcs8 -topk8 -in server.key -out server.pk8 -nocrypt转换。 - 证书编码混淆:PEM是Base64文本格式,DER是二进制格式。用
-outform DER可以互相转换。我碰过一个Java环境只认DER,折腾了半天。 - 密钥长度与性能:双向认证场景每建立一个连接就要做一次私钥签名,密钥越长CPU消耗越大。实测RSA 2048和ECDSA P-256相比,后者握手速度快了大概3倍。如果你对性能敏感,可以考虑用ECDSA。
- 通配符证书:CSR的CN里填
*.example.com可以匹配所有子域名,但注意浏览器对通配符的限制——只能匹配一级子域名,不能匹配两级。
这张图把三个步骤串联起来了。你可以看到每个阶段的输入输出是什么。我建议你在第一次做双向认证时,手动敲一遍这三条命令,感受一下证书是怎么从无到有的。相信我,这比任何GUI工具都能帮你理解TLS的信任模型。
另外说个经验:自签名证书的《基本约束》扩展默认是缺失的,这意味着它不能当CA去签发别的证书。如果你要做两级CA体系(根CA+中间CA),记得在生成证书时加上 -extensions v3_ca。不过那是更后面的内容了,咱们先把基础知识扎牢。