从踩坑到精通:我的Windows+OpenSSL自建CA证书之旅,以及如何用它给Nginx签发带SAN扩展的HTTPS证书

张开发
2026/4/19 14:37:56 15 分钟阅读

分享文章

从踩坑到精通:我的Windows+OpenSSL自建CA证书之旅,以及如何用它给Nginx签发带SAN扩展的HTTPS证书
从踩坑到精通Windows下用OpenSSL打造私有CA并签发带SAN扩展的HTTPS证书那是个令人抓狂的周五下午测试团队突然报告所有Chrome浏览器都在疯狂报错NET::ERR_CERT_COMMON_NAME_INVALID而我们的内部管理系统上线截止时间就在两小时后。作为项目里唯一稍微懂点证书的人我被迫开始了这场与OpenSSL的深度较量——不仅要快速生成可用的HTTPS证书还得让它们支持多域名和IP访问。下面就是我用血泪教训换来的完整实战指南。1. 环境准备别在第一步就掉坑里在Windows上玩转OpenSSL就像带着镣铐跳舞稍有不慎就会遇到路径问题。我最初直接从官网下载了预编译的Win64安装包结果发现默认配置根本不适合创建CA体系。经过三次重装后终于整理出这套可靠的环境方案# 推荐使用这个经过验证的目录结构 E:\OpenSSL ├── bin # 存放openssl.exe ├── conf # 存放openssl.cnf ├── certs # 最终证书存放处 └── private # 所有私钥的保险箱关键提示永远不要将私钥文件放在可能被同步到云盘的目录我因此差点导致内部系统私钥泄露配置环境变量时90%的报错都源于openssl.cnf路径设置错误。正确的姿势应该是$env:OPENSSL_CONF E:\OpenSSL\conf\openssl.cnf cd E:\OpenSSL\bin常见踩坑点路径中包含空格或中文绝对致命使用32位版本处理大密钥时崩溃系统自带老版本OpenSSL造成冲突2. 创建根证书建立你的私人认证帝国2.1 生成CA私钥的生死抉择openssl genrsa -aes256 -out private/ca.key.pem 4096当这个命令出现在屏幕上时我根本没想到接下来会面临什么选择2048位还是4096位后者更安全但性能略差AES加密密码到底设多复杂太简单会被爆破太复杂自己都记不住私钥文件权限怎么控制Windows的ACL设置让我研究了半小时最终我的选择是4096位RSA密钥虽然内部系统不需要这么高强度但考虑到未来扩展密码短语采用12位大小写数字组合并保存在加密密码管理器权限设置对private目录设置仅管理员可访问2.2 自签根证书的艺术生成CSR时那些DN字段差点让我怀疑人生openssl req -new -key private/ca.key.pem -out ca.csr \ -subj /CCN/STShanghai/LPudong/OMyCorp/OUDevSecOps/CNMyCorp Root CA各字段含义的深度解析字段示例值实际意义易错点CCN国家代码必须ISO 3166标准STShanghai省份不能用缩写OMyCorp组织名称后续不能修改CNMyCorp Root CA通用名称必须包含Root CA字样最后的自签名命令藏着时间陷阱openssl x509 -req -days 3650 -sha256 -extensions v3_ca \ -signkey private/ca.key.pem -in ca.csr -out certs/ca.crt血泪教训有效期不要超过398天否则Chrome 58版本会直接拒绝我最初设置的3650天导致全员无法访问3. 签发服务器证书SAN扩展才是终极考验3.1 密钥生成的新认知传统教程都教这样生成服务器密钥openssl genrsa -out private/server.key 2048但实际生产环境应该# 更安全的密钥生成方式 openssl ecparam -genkey -name secp384r1 -out private/server.key openssl req -new -key private/server.key -out server.csr ...密钥类型对比表类型示例命令安全性兼容性性能RSA 2048genrsa -out key.pem 2048中完美快RSA 4096genrsa -out key.pem 4096高完美慢ECDSA secp384r1ecparam -genkey -name secp384r1极高现代浏览器最快3.2 SAN扩展配置的魔鬼细节这就是让我周五加班到凌晨的罪魁祸首正确的SAN扩展文件应该是这样# server.ext authorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsagedigitalSignature,nonRepudiation,keyEncipherment extendedKeyUsageserverAuth subjectAltNamealt_names [alt_names] DNS.1internal.app.com DNS.2*.test.app.com IP.1192.168.1.100 IP.210.0.0.1签发时那个要命的命令openssl x509 -req -days 365 -CA certs/ca.crt -CAkey private/ca.key.pem \ -CAserial serial -in server.csr -out certs/server.crt -extfile server.ext常见SAN配置错误遗漏IP地址导致内网访问报错使用通配符证书但忘了基础域名Chrome要求必须包含请求的精确域名4. Nginx配置当证书遇到现实世界以为有了证书就万事大吉看看这个让我调试到凌晨三点的配置server { listen 443 ssl; server_name internal.app.com; ssl_certificate /path/to/server.crt; ssl_certificate_key /path/to/server.key; # 这些参数才是性能关键 ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; # OCSP装订能提升30%握手速度 ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 valid300s; }性能优化对比测试配置项默认值优化值QPS提升会话缓存无50MB40%TLS协议全支持仅1.215%密码套件全部精选5个20%OCSP装订关闭开启30%当一切终于跑通时Chrome那个绿色的小锁图标是我见过最美的风景。不过第二天早上测试同事就报告iOS设备无法访问——原来还得处理证书链问题。但这就是另一个故事了...

更多文章