ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenSSL自签名证书生成与配置指南:从私钥到HTTPS落地

OpenSSL自签名证书生成与配置指南:从私钥到HTTPS落地 自己动手给开发环境签个证用OpenSSL生成自签名证书这事我干过不下几十次了。每次换机器、换项目、重装环境第一件事就是把这套流程再走一遍。说实话OpenSSL的命令行工具给人的第一印象并不友好参数又多又拗口但一旦理解它背后那条逻辑线——私钥、请求、签发你会觉得它其实是一个非常有条理的工具。这篇文章我想把自己积累下来的完整流程、参数细节、排坑经验整理出来尤其是Windows环境下那点糟心事尽量让你看完之后不用再搜别的文章。自签名证书适合谁简单说一切不需要第三方信任背书、只想让通信加密的场景。本地开发调试HTTPS、内网服务之间的TLS加密、测试环境模拟生产证书、甚至给Git仓库做签名都是它的典型用途。它解决的核心问题就是让你在没有商业CA证书、没有DNS域名控制权、甚至完全离线的环境里也能快速跑起TLS加密通信。准备好我们从为什么要自签名说起再到具体命令、参数解释、格式转换和排坑实录一条龙讲完。1. 自签名证书是干嘛的先想清楚再动手1.1 自签名证书的三个典型场景很多人一提到证书就觉得是网上那个要花钱买的东西其实证书的本质就是一对密钥加一段身份信息打包。自签名证书的核心特征是签发者和持有者是同一个主体没人替你背书。这听起来像自己给自己写介绍信但在很多场景下完全够用。我在实际工作中用到自签名证书最多的场景有三个。第一个是本地开发调试比如你跑了一个Vue或React项目要接HTTPS接口调试或者要给前端页面配Service Worker、音视频权限这些必须在安全上下文里才生效的功能这时候用自签名证书在本地起一个https://localhost问题瞬间解决。第二个是内网服务加密公司内网的API网关、监控面板、内部软件源只要服务器和客户端都在可控网络里自签名证书就能加密通信没必要为内网服务专门买证书。第三个是测试环境模拟在CI/CD流水线里测试TLS握手、测试证书过期逻辑、测试双向认证mTLS自签名证书让你零成本造一大堆不同情况的证书。1.2 自签名证书和CA证书的区别这里有必要说清楚一个概念因为很多人被浏览器红色警告搞怕了。CA证书和自签名证书在加密强度上没有本质区别用的都是同一套非对称加密算法。真正的区别在于信任链CA证书的信任链顶端是预装在系统或浏览器里的根证书浏览器一看这证书的上级是我不认识的机构再往上追最终能追到我信任的根证书就放行了。自签名证书没有上一级自己就是根浏览器不认识它自然警告。这个机制用我自己的话说就是CA证书是熟人介绍自签名证书是自我推荐。你给你的项目签一个自签名证书浏览器不认识你当然会阻拦但只要你在系统里把这张证书手动加入信任列表浏览器就不再警告了。很多开发者搞不清楚这点以为自签名证书不安全其实TLS加密本身是一致的。想明白了这些下面我直接进入实操环节。2. 环境准备别让版本问题毁了你的一天2.1 查看OpenSSL版本动手之前先敲一行命令看看手头的OpenSSL是什么版本openssl version正常会输出类似OpenSSL 3.0.12 24 Oct 2023或OpenSSL 1.1.1w 11 Sep 2023的结果。为什么我强调这一步因为OpenSSL 1.1.1和3.x在命令细节上有些差异比如部分废弃参数提示方式不同某些算法默认策略变了。你要是照着老教程敲命令发现报错八成是版本差异。在Windows上如果敲openssl version直接提示不是内部或外部命令说明OpenSSL还没装进系统PATH。有两个通用但可靠的解决办法第一个是装Windows版OpenSSL建议选slproweb提供的安装包注意区分Win64和Win32第二个是用Git自带的OpenSSLGit Bash环境里就内置了一份在Git Bash里直接openssl version就能看到。2.2 Windows下的安装与PATH配置Windows下安装OpenSSL最让人头疼的不是安装本身而是装完之后PATH环境变量里可能同时存在多个版本的OpenSSL。这个问题我后面专门有一节讲先说说怎么一开始就避免。若你用的是slproweb安装包安装时它会问你Copy OpenSSL DLLs to Windows system directory这个可以跳过。安装完成后把C:\Program Files\OpenSSL-Win64\bin添加到系统PATH。注意一定要在系统变量里改不要只在用户变量里加否则有些以系统服务方式运行的程序根本读不到新版本。这里再提醒一个我踩过的坑Windows 10及以上系统里C:\Windows\System32可能放着别人塞进去的旧版libcrypto-3.dll或libssl-3.dll。如果你的系统PATH里System32排在OpenSSL的bin之前而你又把DLL装进了系统目录那么不管你怎么配置openssl命令的指向程序实际加载的DLL可能还是旧版。建议检查一下系统目录里有没有这些DLL文件有且不是你主动放的话趁早删掉或替换成一致版本。2.3 版本选择的几个建议win64 openssl v1.1.1w这个热词说明不少人还在用1.1.1系列我能理解为什么——1.1.1w是1.1.1系列最后的版本陪伴了很多人的项目。但从维护角度说1.1.1系列已经停止支持若只是本地生成证书用什么版本影响不大若要长期用于生产环境我更推荐用3.x LTS版本因为安全更新和算法策略更贴近当前生态。如果你同时装了两个版本建议不要手动改PATH来回切。正确的做法是在你需要用的那一次Shell会话里临时把目标版本路径提到最前面比如在CMD里执行set PATHC:\Program Files\OpenSSL-Win64\bin;%PATH%然后在同一个窗口里再openssl version确认免得切来切去搞混环境。3. 核心三件套私钥、CSR、证书3.1 生成RSA私钥一切的起点自签名流程里裁第一块拼图是私钥。私钥不是随便生成的它包含模数、公钥指数、私钥指数等一组数学结构。OpenSSL里生成RSA私钥最传统的命令是openssl genrsa -out server.key 2048这条命令意思很直白生成2048位的RSA私钥写入server.key文件。2048是目前的最低配置如果你胆子大用4096也可以加密强度更高但握手性能稍慢。我的建议是本地开发用2048够了真实生产环境建议4096。另一条更现代的命令是genpkeyopenssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server.key两条命令生成的私钥格式略有不同。genrsa输出的是传统的BEGIN PRIVATE KEYPKCS#1格式genpkey输出的是BEGIN PRIVATE KEYPKCS#8格式。不过OpenSSL在读取时会根据头自动识别很多场景两者混用没太大问题。如果后面要转成Java用的PKCS#8直接用genpkey更省事。私钥生成之后千万别忘了设置文件权限。Linux/macOS上执行chmod 600 server.keyWindows上没有这么细的权限字面量但你可以右键文件在安全选项卡里确认只有当前用户和Administrator能读。私钥泄露等于你的加密体系彻底沦陷这个再怎么强调都不为过。3.2 生成证书签名请求CSR有了私钥下一步是生成CSRCertificate Signing Request证书签名请求。CSR相当于一张个人信息表里面写着你要给证书填的身份信息比如国家、省份、组织名、域名等。传统交互式流程一行命令就能启动openssl req -new -key server.key -out server.csr命令执行后OpenSSL会像查户口一样问你一串字段Country Name两个字母的国家代码中国填CNState or Province Name省份可以填全称Locality Name城市Organization Name组织名公司名或个人名字Organizational Unit Name部门名可以不填Common Name这是最重要的字段填你要加密的域名或IP如果你不想每次都被交互式提问打断可以用-subj参数一步到位openssl req -new -key server.key -out server.csr \ -subj /CCN/STBeijing/LBeijing/OMyDev/CNlocalhost注意/CNlocalhost里的localhost这个字段必须和你要访问的域名完全一致。你要是给https://192.168.1.10访问CN就得填192.168.1.10否则浏览器会提示证书与站点不匹配。还有一个必须提的字段Subject Alternative NamesSAN也就是证书备选域名。现代浏览器对SAN的要求比CN严格得多Chrome从某个版本开始基本不看CN只想看SAN。如果你的证书要同时支持localhost和api.dev.local两个域名就得在请求里加上SAN扩展。用配置文件方式最清晰先写一个server.cnf[req] distinguished_name dn req_extensions v3_req [dn] CN localhost [v3_req] subjectAltName alt_names [alt_names] DNS.1 localhost DNS.2 api.dev.local IP.1 127.0.0.1然后执行openssl req -new -key server.key -out server.csr -config server.cnf这样生成的CSR里才带着SAN信息。不写SAN直接做自签名证书遇到Chrome、Firefox大概率直接红屏这是很多初学者最容易栽的坑。3.3 一步到位直接签发自签名证书如果你只是想要一张证书不需要走生成CSR再拿去CA签的流程那OpenSSL给了一条捷径用req命令加-x509参数一步生成私钥自签证书。最经典的两步合并写法是openssl req -x509 -newkey rsa:2048 \ -keyout server.key -out server.crt \ -days 365 -nodes \ -subj /CCN/STBeijing/LBeijing/OMyDev/CNlocalhost拆开解释一下-x509告诉OpenSSL直接输出自签名证书而不是CSR-newkey rsa:2048同时新生成一把2048位RSA私钥省得先单独生成-keyout server.key私钥输出到server.key-out server.crt证书输出到server.crt-days 365证书有效期365天具体天数看你需要最长时间按OpenSSL版本策略来-nodes这个参数全称是No DES也就是不加密私钥文件不给你设置口令。如果不加-nodesOpenSSL会提示你设置一个密码以后每次加载私钥都要输入密码。对大多数服务器自动启动场景这极其不方便所以我一般都会加上-nodes如果你想先生成私钥再基于已有私钥自签证书可以分开两步openssl req -new -key server.key -out server.csr -subj /CNlocalhost openssl x509 -req -in server.csr -signkey server.key -days 365 -out server.crt但注意一种微妙差异如果用了-x509 -newkey一步生成证书里是否包含你要的SAN扩展取决于OpenSSL版本和配置文件。稳妥起见我在正式场景里倾向于CSR和自签分开做因为生成CSR时我能通过-config显式控制SAN扩展。如果你想在一步命令里也带上SAN可以配合开头提到的server.cnfopenssl req -x509 -newkey rsa:2048 \ -keyout server.key -out server.crt \ -days 365 -nodes \ -subj /CNlocalhost \ -config server.cnf这里有个小坑-subj和-config里的[dn]同时存在时-subj优先级更高。也就是说HTTP的CN以-subj为准但SAN扩展依然来自配置文件。我自己测试下来这套组合是最可靠的。4. 命令参数详解看懂每个选项再复制4.1 常用参数速查表很多教程让你复制命令但你不知道参数是什么意思一旦报错就懵了。这里我整理了一张高频参数速查表把常用选项干什么用的都列清楚照着查就行。参数作用常见取值-x509输出自签名证书而非CSR无-newkey生成新私钥rsa:2048,rsa:4096-keyout私钥输出路径任意文件名如server.key-out证书或CSR输出路径如server.crt或server.csr-days证书有效天数365、730等-nodes私钥不加密不设密码无-subj一行设置证书主体信息/CCN/STBeijing/CNlocalhost-key使用已有私钥如server.key-new创建新的CSR无-sha256指定摘要算法sha256,sha384-config指定配置文件如server.cnf-copy_extensions从CSR复制扩展到新证书copy4.2 几个容易出错的参数细节-nodes参数我之前解释过但它的名字确实起得怪很多人第一次看到以为是不做任何事。其实nodes是no DES的缩写意思是别给我上密码。你要是手痒不加-nodes私钥文件会被加密保存启动Nginx或Tomcat时就会提示输入密码。对自动化部署来说这就是噩梦。-days参数在OpenSSL主版本之间行为很一致但有个细节你设置的天数不能超过配置文件里约定最大值。默认情况下自签名证书最大年限通常是825天OpenSSL 3.x里有些策略更严格或者1095天具体看版本策略。要签几年有效期的证书建议先测试别指望命令行里-days 10950一定成功。还有个常见坑在-subj里。/CNlocalhost和/CN localhost等号前后多空格在OpenSSL里通常会被容错处理但我在Windows的CMD里见过直接照抄配置文件格式导致解析失败的情况。建议写-subj时不要在任何值两边加多余空格。我再强调一次-sha256很重要。老教程里很多都用-md5或-sha1现在这俩摘要算法在安全性上已经过时了。生成证书时主动加上-sha256不然OpenSSL默认摘要算法可能随版本变化让人心里不踏实。5. 证书验证与格式转换5.1 查看证书内容证书生成出来不是完事了你得确认内容对不对。查看证书最常用命令是openssl x509 -in server.crt -text -noout-noout的意思是不输出原始证书的Base64编码只打印可读的内容摘要。你会看到证书的版本、序列号、签名算法、颁发者、有效期、公钥信息以及扩展字段。重点关注三件事有效期是否按预期设置CN和SAN是否包含你需要的域名签名算法是不是sha256WithRSAEncryption而不是老掉牙的sha1WithRSAEncryption。在Windows上如果你懒得敲命令双击.crt文件也能用Windows自带的证书查看器看到大部分信息但SAN字段和扩展信息还是命令行看得全。5.2 私钥与证书匹配检查有一回我把私钥和证书搞混了私钥是A的证书是B的服务起半天起不来报错信息又模棱两可。后来学到一招比较私钥和证书的模块数modulus一致就说明是同一对。openssl x509 -in server.crt -noout -modulus | openssl md5 openssl rsa -in server.key -noout -modulus | openssl md5两边输出的MD5值如果完全一致就说明私钥和证书匹配。因为从数学上讲证书里的公钥是从这同一个RSA模数里推导出来的模块数必然相同。这个排查手段在配置Nginx、Apache报私钥和证书不匹配时非常救命。5.3 PEM、DER、PFX格式转换OpenSSL默认输出的是PEM格式也就是以-----BEGIN CERTIFICATE-----开头的Base64文本。但很多平台不认PEM常见两种转换需求第一是PEM转DERJava里常用DER格式openssl x509 -in server.crt -outform DER -out server.der第二是生成PFX/P12用于Windows服务器或导入浏览器openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx注意执行后OpenSSL会提示你设置导出密码。有些教程让你直接回车空密码但Windows上很多工具不接受空密码的PFX我建议还是设置一个临时密码用的时候输一次就行。还有一个反向需求从PFX里提取私钥和证书。这在从Windows证书库迁移到Linux服务器时很常见openssl pkcs12 -in server.pfx -nodes -out server.pem-nodes在这里同样表示不加密提取出的私钥。提取出来的server.pem文件其实既含私钥又含证书你可以用openssl rsa和openssl x509继续拆分也可以在某些不改格式的服务器上直接使用。6. 排坑实录版本不匹配和Windows路径问题6.1 版本不匹配错误到底是谁加载了错误的DLLopenssl version mismatch built against 30000070, you have 38500000这类报错我愿称之为Windows上最烦人的OpenSSL问题之一。理解它之前你得知道一个背景很多软件不是外部调用openssl.exe命令的而是直接动态加载libssl和libcrypto这两个库。假如某个程序在编译时连的是OpenSSL 3.0.7版本号0x30000070运行时却在系统或PATH的某个目录里找到了另一个版本比如0x38500000两边一校验对不上直接报mismatch。这种问题常见的触发原因是本机装了多个OpenSSL发行版或者某个软件自己带了一份DLL同时又在PATH里引用了另一份。排查思路如下先用where openssl看命令指向哪个目录如果出现多行说明PATH里有多个OpenSSL。用openssl version -d查看OpenSSL编译时的默认路径以及openssl version -a看看完整的编译信息。搜索整个系统里有多少个libssl-3.dll或libcrypto-3.dll用Everything这类工具直接全盘搜看哪些目录有。顺带查一下C:\Windows\System32和SysWOW64这两个目录很多软件会在这里塞DLL。定位到多版本来源后解决办法是留一个你明确要用的版本把其他版本的安装目录从PATH里拿掉或者把多余的DLL文件移走。如果是某个软件自带的DLL和你的环境冲突那就看能否升级或降级该软件。6.2 PATH配置导致的版本错乱Windows上另一个高频问题就是PATH顺序。where openssl命令很有用它显示的路径顺序就是系统查找命令的顺序。如果你同时装了OpenSSL 1.1.1w和3.x在CMD里openssl可能命中1.1.1但在某个IDE的终端里因为PATH继承方式不同又命中了3.x造成在命令行敲和从程序里调用版本不一致的错觉。这里有一个我总结的最稳做法在系统PATH里只保留一个OpenSSL的bin目录另一个留着安装但别加进PATH。真要临时用另一个版本就在单个会话里用set PATH...;%PATH%压到最前面。别在PATH里留两条OpenSSL这是自找麻烦。顺带说一句Git Bash/WSL里的OpenSSL编译环境跟Windows原生二进制不是一回事。你在Git Bash里用openssl version看到的可能是Linux/Unix风格编译的版本其DLL依赖动态库和Windows版走的完全不同的加载路径。所以在Git Bash里跑的openssl和Windows服务直接调用的openssl可能是两个东西排查时要先确认你现在用的是哪个环境。6.3 常见问题速查表我把这几年遇到的高频问题汇总成一张表方便你直接对照排查现象可能原因解决思路openssl命令找不到未安装或未加入PATH装OpenSSL并配系统PATHversion mismatch built against ...多版本DLL冲突程序加载了错误DLL全盘搜libssl-3.dll统一版本证书生成后浏览器报不安全根证书未信任或SAN缺失或CN不匹配手动信任证书生成时加SAN扩展私钥文件需要密码服务启动卡住生成时没加-nodes私钥被加密用openssl rsa -in server.key -out server.key.decrypted解密或QA生成时加-nodes证书与私钥不匹配文件错位或误操作用modulus比对确认提示out of memory或算法不支持旧版本OpenSSL不支持高位数RSA密钥升级OpenSSL或降低密钥位数证书有效期不够长配置文件限制或版本默认策略查版本上限用-days合理设置6.4 Windows下升级OpenSSL的几个注意点关于openssl升级windows这个热词围绕它的坑不少我单独说几句。如果你现在用的是1.1.1w想升到3.x先做三件事第一备份旧版本的bin目录或者干脆通过安装包卸载干净不要让两个版本共存于PATH。第二确认老项目是否依赖OpenSSL 1.1.1特有的算法策略。OpenSSL 3.x把很多算法的默认安全级别提高了比如某些老机器上生成的1024位密钥在3.x里默认直接拒绝使用这类问题在升级后才会暴露。第三升级后务必跑一遍openssl version -a确认编译特征和DLL路径是你预期的。我在Windows上升级OpenSSL踩过最大的坑是升级后某个老服务程序怎么都起不来日志里只有一条模糊的0xc000007b错误。查了半天原因是它找的DLL版本从3.0.7变成了3.0.12而该程序对DLL API版本有硬编码的匹配检查。最后我把它依赖的DLL复制到了它的运行目录才解决了问题。这类问题没有万能公式思路就是先看错误再查依赖然后统一版本。7. 从证书生成到落地使用几个服务器的配置参考既然证书都签出来了不放几个落地配置说不过去。我自己最常用的两个场景是Nginx和Tomcat这里简单给个配置骨架。Nginx配置HTTPS的核心片段server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/server.crt; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location / { proxy_pass http://127.0.0.1:8080; } }Tomcat配置HTTPS的核心片段在server.xml里设置Connector port8443 protocolorg.apache.coyote.http11.Http11NioProtocol maxThreads200 SSLEnabledtrue SSLHostConfig Certificate certificateKeystoreFileconf/server.pfx certificateKeystoreTypePKCS12 certificateKeystorePasswordyourpassword / /SSLHostConfig /Connector注意Tomcat用PFX格式最方便就是因为Java的KeyStore天然支持PKCS12。把之前生成的PFX文件丢到Tomcat的conf目录配上密码就行。如果你想让浏览器不再跳红色警告还有个技巧把自签名证书导出然后在系统里手动安装并把它放入受信任的根证书颁发机构。操作路径是双击server.crt选择安装证书存储位置选本地计算机然后手动选择受信任的根证书颁发机构。安装之后本机浏览器再访问就不会提示证书不可信了但别的机器访问你的服务照样警告因为每台机器的信任列表是独立的。再补充一个更进阶的用法做双向TLS认证mTLS。你自签一张CA根证书然后用它签多个客户端证书服务器端配置ssl_verify_client on和ssl_client_certificate指向根证书。客户端连上来时必须出示由你签发的客户端证书这样就能实现只有持有合法证书的客户端才能访问服务。这套玩法在微服务内部认证、物联网设备接入控制里非常常用而它的基础就是你能熟练地用OpenSSL签发证书。最后分享一点个人心得实际操作中我发现最容易出问题的不是命令本身而是你对自己要签的证书长什么样没有一个清晰的预期。建议每次动手前先在纸上写清楚CN是什么、SAN里有哪些域名、有效期多少天、私钥要不要密码、最终给谁用。想清楚了命令自然就顺了。还有个小习惯值得养成在跑正式命令之前先在临时目录里用一套测试值练一遍确认命令无误后再换成真实信息操作。尤其是涉及-subj、-config这些能被复制粘贴搞错的参数时先跑通再上手能省下大量时间。自签名证书这套东西一遍用不明白用几次就有肌肉记忆了。希望这篇写到的流程和坑能让你少走几趟弯路。
返回列表