
2023年全球自签名证书签发量超过47亿张,其中超过六成从未离开过生成它的那台计算机。本地证书制作教程的搜索量同期上涨了210%,但绝大多数教程仍在教人使用十年前就已过时的OpenSSL命令。
本地证书制作这个领域,存在一个被忽略的事实:多数人需要的不是一张“合法”的证书,而是一张“恰好能跑通当前环境”的证书。两者之间的差异,决定了教程该写什么。
问题一:本地证书制作教程里,为什么openssl req -x509这条路正在失效?
OpenSSL的x509子命令可以一条命令生成自签名证书,这个做法在过去十五年里遍布各种本地证书制作教程。但Chrome 58之后,浏览器对证书的subjectAltName(SAN)扩展做了强制校验——只填CN(Common Name)的证书直接报NET::ERR_CERT_COMMON_NAME_INVALID。而大量旧教程仍然只演示-subj "/CN=localhost"这种写法。
技术原理层面,Chrome和Firefox从2017年起执行CA/Browser Forum的基线要求,把SAN作为唯一身份标识来源。CN字段只是历史遗留的展示项。一张没有SAN的证书,在RFC 2818标准下本身就是不合规的。这意味着,那些教你用一条openssl命令生成证书的本地证书制作教程,产出的证书在主流浏览器上根本无法通过校验。
正确做法是必须带上-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"参数。这个细节,直接筛掉了一批不更新的教程。
问题二:mkcert这类工具,到底在底层做了什么让本地证书制作变简单?
mkcert是Filippo Valsorda写的一个Go程序,它解决的核心问题不是“生成证书”,而是“让生成的证书被本机信任”。坦白讲,生成一张自签名证书从来不难,难的是把它安装到系统信任库里,还要让浏览器和操作系统都认。
mkcert的工作机制分三步。第一步,首次运行时在本地创建一个CA(证书颁发机构)——具体位置在~/.local/share/mkcert/rootCA.pem和rootCA-key.pem。第二步,把这个CA证书安装到系统信任库:macOS上调用security add-trusted-cert,Linux上复制到/usr/local/share/ca-certificates/并执行update-ca-certificates,Windows上通过CertAddCertificateToStore写进受信任根证书存储。第三步,用户请求为localhost或某个IP生成证书时,mkcert用本地CA签发,同时自动填充SAN,证书有效期设为十年。
这个过程本质上是在本机搭建了一个私有PKI(公钥基础设施)。你的电脑上多了一个只属于本机的根CA,所有由它签发的证书都自动被信任。安全性方面,这个CA的私钥存在本地,只要不泄露,外部攻击者无法用它伪造证书。但如果有人拿到你的rootCA-key.pem,就能对任意域名签发你本机信任的证书——这是mkcert文档里明确警示的风险。
问题三:本地证书制作教程里,为什么很少提到Ed25519和RSA的差别?
绝大多数本地证书制作教程默认使用RSA 2048位密钥。从算法原理看,RSA基于大整数分解难题,密钥越大越安全,但签名和验签速度也越慢。Ed25519基于椭圆曲线Curve25519的EdDSA签名方案,128位安全强度即可达到RSA 3072位的安全水平,密钥更短、签名更快。
2020年之后签发的TLS证书中,Ed25519占比从不到1%上升到约8%。Cloudflare、Google等公司已在生产环境大量使用Ed25519。但本地证书制作教程几乎不涉及这个选项。原因是多方面的:部分旧版Windows Server不支持Ed25519,某些嵌入式设备只认RSA。如果你的环境是纯现代的——Windows 10 1903以上、macOS 10.14以上、Linux内核4.4以上——使用Ed25519完全没问题。
生成Ed25519本地证书的命令其实更短:openssl req -x509 -newkey ed25519 -keyout key.pem -out cert.pem -days 365 -addext "subjectAltName=DNS:localhost"。简单来讲,该升级密钥算法了。
问题四:内网IP证书,比如192.168.x.x,本地证书制作教程能覆盖吗?
能,但做法和域名不同。IP地址在证书中需要放在SAN的iPAddress字段,而不是DNS字段。openssl的写法是-addext "subjectAltName=IP:192.168.1.100"。mkcert则不支持IP地址,它只处理DNS名称——这是一个被很多本地证书制作教程忽略的限制。
技术背景是,RFC 5280规定SAN可以包含iPAddress类型,但浏览器对IP地址证书的校验策略更严格。Chrome要求IP证书必须是精确匹配,不支持通配符。Safari在iOS 13之前甚至不信任任何IP地址的TLS证书。如果你在测试环境中需要给内网IP签发证书,建议直接用openssl命令手动指定IP SAN,或者改用自建PKI的完整流程来处理。
另一个细节:证书有效期。Let's Encrypt的证书是90天,本地证书制作教程经常建议365天或更长。但如果你在macOS上通过钥匙串信任了一个自签名证书,系统会在证书过期后仍然保持信任状态,直到手动删除——这个行为与预期不符,容易留下安全隐患。
本地证书制作教程该不该推荐GUI工具?
KeyStore Explorer、XCA、Certify这类图形化工具在Windows用户中占有一定市场。XCA支持完整的CA管理和证书模板,界面类似数据库客户端,学习曲线不算平缓。但说实话,命令行工具在本地证书制作场景中仍然不可替代——自动化脚本、CI/CD流水线、Docker容器启动时挂载证书,这些场景里GUI工具没有位置。
一个折中的趋势是:教程先讲命令行原理,再给GUI选项。只讲GUI的教程,读者一旦遇到脚本化需求就会卡住。只讲命令行的教程,对于不熟悉终端的开发者——尤其是前端开发做本地HTTPS调试时——门槛又太高。
本地证书制作教程的核心价值,不在于给出一个能跑的命令,而在于让读者理解这张证书在本机信任链中的位置。理解了这一点,换工具、换算法、换有效期,都不会再出现“教程里明明是好的,我跑就报错”的困惑。