bg-tutorials

如何使用OpenSSL生成自签名证书?

自签名证书是您自己签发给自己的证书,而不是从证书颁发机构购买的。浏览器不会自动信任它,因此它不适合用于公开网站,但它是在开发机器、预发布环境、内部仪表盘或任何不面向公开互联网的服务上启用 HTTPS 的最快方式。

本指南将向您展示如何使用 OpenSSL 创建自签名证书,适用于 Windows、Linux 和 macOS。三者的命令是相同的。您还将看到如何检查生成的证书是否真正可用,以及如何让自己的机器信任它,从而消除浏览器警告。

什么是自签名证书

自签名证书是使用自身私钥签名的数字证书,而不是由受信任的证书颁发机构(CA)签名。从密码学角度来看,它是一张普通的 X.509 证书:加密流量的效果和购买来的证书完全一样。它所缺乏的是信任链。您自己机器之外的任何设备都没有理由相信它,因此浏览器会显示警告,除非您另行告知。

这使得自签名证书非常适合以下场景:

  • 本地开发,您需要 HTTPS 以确保 Cookie、Service Worker 或支付 SDK 的行为与生产环境一致。
  • 内部服务,例如内网仪表盘、监控面板,或私有网络上的设备管理界面。
  • 测试和预发布,您希望在不花费证书的情况下演练一套 TLS 配置。
  • 代理背后的源服务器,接受后端环节上不受信任的证书,例如以 Full 模式运行的 Cloudflare。

对于真实访客将访问的任何内容,它都是不合适的工具。我们将在下文的”何时不应使用自签名证书”部分详细讨论这一区别。

开始之前:检查您的 OpenSSL

您需要 OpenSSL 命令行工具。请先确认您所拥有的版本:

openssl version
  • Linux:OpenSSL 已在大多数发行版中预装。如果没有,请参阅我们的指南如何在 Ubuntu 上安装 OpenSSL
  • Windows:OpenSSL 不是自带的。请按照我们的说明如何在 Windows 上安装 OpenSSL,然后在命令提示符或 PowerShell 中运行该命令。
  • macOS:Apple 将 LibreSSL(OpenSSL 的一个分支)作为内置的 openssl 命令提供,因此运行结果会显示类似LibreSSL 3.3.6的内容,而不是 OpenSSL 版本号。

本指南中的主要命令在 LibreSSL 3.3.6 以及当前版本的 OpenSSL 上都可以正常运行,因此 Mac 用户可以使用内置工具。如果您更希望使用真正的 OpenSSL(下面的一些可选命令需要它),请使用 Homebrew 包管理器进行安装,并通过完整路径调用它:

brew install openssl@3
/opt/homebrew/opt/openssl@3/bin/openssl version

在 Intel 芯片的 Mac 上,路径则是 /usr/local/opt/openssl@3/bin/openssl。有关如何解读输出结果的更多详情,请参阅我们的指南如何检查您的 OpenSSL 版本

如何使用 OpenSSL 创建自签名证书

第一步:打开终端

在 Linux 上,按下Ctrl + Alt + T,或在应用程序菜单中搜索”Terminal”(终端)。在 macOS 上,打开应用程序,然后是实用工具,再打开终端,或按下Cmd + Space并输入”Terminal”。在 Windows 上,按下Win + R,输入cmd,然后按 Enter。

命令提示符终端窗口

第二步:切换到您希望存放文件的文件夹

OpenSSL 会将输出写入您当前所在的目录,而不是 OpenSSL 安装所在的目录。请为这个证书创建一个文件夹并进入其中,以便密钥和证书能够存放在您可以找到的位置:

mkdir my-cert
cd my-cert

在 Windows 上,请在命令提示符中使用相同的两条命令。请不要在 OpenSSL 程序文件夹内运行这些命令:在 Windows 上,该目录通常不允许普通用户写入,而且把密钥和二进制文件混在一起也很容易丢失。

第三步:运行证书命令

这条单一命令会同时生成私钥和自签名证书。请将example.comwww.example.com替换为您服务实际使用的域名:

openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -addext "subjectAltName=DNS:example.com,DNS:www.example.com" -addext "basicConstraints=critical,CA:FALSE" -addext "extendedKeyUsage=serverAuth"

请将其保持在一行内。命令提示符和 Unix shell 使用不同的换行续行符,而单行命令在任何环境下都有效。出于同样的原因,请使用双引号而非单引号:命令提示符不会将单引号视为引用符号。

以下是各部分的作用:

  • req -x509:生成一个完成的、已签名的证书,而不是证书签名请求。
  • -newkey rsa:2048:在同一命令中创建一个新的 2048 位 RSA 私钥。2048 位是目前的最低标准,也是合理的默认值。如果您的策略要求更大的密钥,可以使用rsa:4096,但代价是握手速度会变慢。
  • -keyout private.key:私钥文件的名称。
  • -out certificate.crt:证书文件的名称。
  • -days 365:证书的有效期长度。更改此项前,请先阅读下文的有效期部分。
  • -nodes:不加密私钥,使您的 Web 服务器可以启动,而不需要人工输入密码短语。
  • -addext “subjectAltName=…”:证书有效的主机名列表。缺少此项,证书将无法匹配任何域名。
  • -addext “basicConstraints=critical,CA:FALSE”:将该证书标记为终端实体(服务器)证书,而不是证书颁发机构证书。
  • -addext “extendedKeyUsage=serverAuth”:声明该证书用于验证 TLS 服务器身份。Apple 平台将此视为强制要求。
使用 OpenSSL 生成私钥

为什么这三个 -addext 选项很重要

这三个标志是决定证书能否正常工作还是被客户端直接拒绝的关键。它们值得深入理解,因为没有这些标志创建的自签名证书会以三种方式失败,而这些方式很容易被误判。

主机名存放在 Subject Alternative Name 中。浏览器多年前就已停止读取 Common Name 字段,现在只根据 Subject Alternative Name(SAN)扩展来匹配主机名。没有 SAN 的证书无法匹配任何站点,无论 Common Name 看起来多么正确。请列出您将使用的每一个名称,用逗号分隔。对于本地服务,您也可以包含一个 IP 地址:

-addext "subjectAltName=DNS:localhost,DNS:dev.example.com,IP:127.0.0.1"

如果没有 CA:FALSE,OpenSSL 会为您生成一个 CA 证书。req -x509 使用其默认设置时,会将 basicConstraints 设置为critical, CA:TRUE,这描述的是证书颁发机构,而不是 Web 服务器。Chrome 和 Safari 会接受这样一个服务器证书。而 Firefox 不会,会停止并显示MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY。您仍然可以点击”高级”并添加例外,但这相当于绕过一个您已知格式错误的证书,而其他客户端在这方面的判断标准可能各不相同。传入basicConstraints=critical,CA:FALSE可以从源头上避免这种情况。

macOS 自带的 LibreSSL 构建版本在这方面表现有所不同:在使用其默认设置时,它会写入一个不带任何扩展的 X.509 版本 1 证书,因此不会出现 CA:TRUE 的问题,但也不会有 Subject Alternative Name。明确指定这些扩展可以在两种工具上都得到相同的、正确的证书。

如果没有 serverAuth,Apple 平台会拒绝该证书。Apple 发布的受信任证书要求规定,TLS 服务器证书必须携带包含 id-kp-serverAuth OID 的 ExtendedKeyUsage 扩展。没有该扩展的证书在 TLS 策略下的 macOS 证书验证将失败,并显示”Invalid Extended Key Usage for policy”的消息,即使该证书被作为自身的信任锚提供也是如此。Firefox 和 Chrome 更为宽容,会将服务器证书上缺失的 ExtendedKeyUsage 视为可以接受,因此这一点很容易被忽略,直到某台 Mac 或 iPhone 无法连接时才会发现问题。添加extendedKeyUsage=serverAuth在其他平台上不会造成任何影响,而且这本来就是公共 CA 会签发的内容。

第四步:填写证书详情

OpenSSL 会询问构成可分辨名称(Distinguished Name)的各个字段。按 Enter 可以跳过任何一项,但至少要填写一项,并且应将其设为 Common Name。macOS 上的 LibreSSL 构建版本,如果所有字段都留空,会停止并显示”error, no objects specified in config file”,且不会写入任何内容。以下的值只是示例,请使用您自己的信息:

OpenSSL 提示输入证书详情
  • Country Name(国家名称):您所在国家的两字母代码,例如 US。
  • State or Province Name(省或州名称):完整拼写,例如 California。
  • Locality Name(城市名称):您所在的城市,例如 San Jose。
  • Organization Name(组织名称):您的公司或项目名称,例如 Example Inc。
  • Organizational Unit Name(组织单位名称):负责的团队,例如 IT。
  • Common Name(通用名称):主要主机名,例如 example.com。请使用与您在 Subject Alternative Name 列表中排在第一位的名称相同的值。
  • Email Address(电子邮件地址):联系地址,例如 [email protected]。此项为可选。

这里真正重要的只有 Common Name,而且仅仅是作为标签使用:主机名的匹配是由您已经在命令行中设置的 Subject Alternative Name 完成的。其余的都只是描述性信息。

您会注意到该命令从未要求输入挑战密码。这一提示是证书签名请求特有的内容,属于一个已经过时的字段,CA 通常会忽略或拒绝它。由于该命令生成的是一个完整的证书而非一个请求,因此该提示根本不会出现。

第五步:使用前先验证证书

不要跳过此步骤。一个自签名证书可能成功生成,但仍然无法使用,而这个问题只会在稍后以浏览器错误的形式出现。请读取证书内容进行检查:

openssl x509 -in certificate.crt -noout -text

在 X509v3 extensions 部分,您需要确认恰好有以下三项内容:

X509v3 Subject Alternative Name:
    DNS:example.com, DNS:www.example.com
X509v3 Basic Constraints: critical
    CA:FALSE
X509v3 Extended Key Usage:
    TLS Web Server Authentication

如果 Subject Alternative Name 那一行缺失,证书将无法匹配任何主机名。如果 Basic Constraints 显示为CA:TRUE,Firefox 将会因此停止运行。如果 Extended Key Usage 那一行缺失,Apple 平台将拒绝该证书。在任何这些情况下,请删除这两个文件,并在同时包含全部三个-addext选项的情况下重新运行该命令。

在 OpenSSL 3.x 上,您可以只请求这些扩展,而不需要读取整个证书:

openssl x509 -in certificate.crt -noout -ext subjectAltName,basicConstraints,extendedKeyUsage

-ext标志在 macOS 自带的 LibreSSL 构建版本中不存在,运行时会报告”unknown option -ext”。在原装 Mac 上,请使用上文中的-text版本。

要确认证书和密钥是否匹配,请比较它们的模数(modulus)。以下两条命令必须打印出相同的哈希值:

openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5
记事本显示生成的证书文件

证书本身是一个文本文件。在文本编辑器中打开它,可以看到位于 BEGIN CERTIFICATE 和 END CERTIFICATE 行之间的一段 base64 编码内容,这就是您在要求粘贴证书而非上传文件的控制面板中所需粘贴的内容。

命令的变体

不通过任何提示生成证书

对于脚本和 CI 流水线,可以通过-subj提供可分辨名称(Distinguished Name),这样命令就会在无人值守的情况下运行:

openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/C=US/ST=California/L=San Jose/O=Example Inc/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:www.example.com" -addext "basicConstraints=critical,CA:FALSE" -addext "extendedKeyUsage=serverAuth"

使用 EC 密钥而非 RSA

在同等强度下,椭圆曲线密钥比 RSA 更小、更快,而且当前所有主流浏览器都支持它们。P-256 是标准的选择:

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout private.key -out certificate.crt -days 365 -nodes -addext "subjectAltName=DNS:example.com,DNS:www.example.com" -addext "basicConstraints=critical,CA:FALSE" -addext "extendedKeyUsage=serverAuth"

生成结果使用 ecdsa-with-SHA256 进行签名。如果您必须支持较旧的嵌入式客户端或旧版 Java(有时缺乏 EC 支持),请继续使用 RSA。

对于这一项,请使用真正的 OpenSSL。macOS 自带的 LibreSSL 构建版本可以接受该命令,但它会将曲线以一整套显式参数的形式写入证书,而不是标准的 P-256 标识符。RFC 5480 规定证书中不得使用显式形式,而 macOS 本身也会拒绝以这种方式编码的证书。

使用openssl x509 -in certificate.crt -noout -text检查结果:您希望看到的是一行”ASN1 OID: prime256v1″,而不是列出 Prime、A、B 和 Generator 的一个数据块。在原装 Mac 上,请使用上文的 RSA 命令,或者先通过 Homebrew 安装 OpenSSL。

-nodes 还是 -noenc?

这两个标志的作用相同:它们都会阻止 OpenSSL 使用密码短语加密私钥。OpenSSL 3.x 增加了-noenc作为更明确的名称,并将-nodes列为已弃用,尽管它仍然接受该选项。macOS 自带的 LibreSSL 完全不识别-noenc,会报错退出。

本指南使用-nodes,因为它是在您可能遇到的每一种构建版本上都适用的选项,包括原装 Mac。如果您使用的是 OpenSSL 3.x 并希望避免使用已弃用的写法,可以换用-noenc。其他方面不需要任何改动。

如果您完全不使用该标志,OpenSSL 会用您选择的密码短语来加密密钥,随后您的 Web 服务器在每次重启时都会提示输入该密码短语。这在开发证书中通常并不是您想要的行为。

让您的机器信任该证书

一个正确无误的自签名证书仍然会产生浏览器警告,因为没有任何机制被告知要信任它。将其添加到本地信任存储正是消除警告的方法,而这通常正是创建它的初衷。

请仅在您自己控制的机器上执行此操作,并且仅针对您自己生成的证书。一个受信任的证书会在其所命名的每一个站点上受到信任,因此请相应地妥善保管私钥,切勿与他人共享。

macOS 钥匙串(Keychain)

将证书添加到系统钥匙串,并将其标记为受信任的 TLS 证书。系统会要求您输入管理员密码:

sudo security add-trusted-cert -d -r trustRoot -p ssl -k /Library/Keychains/System.keychain certificate.crt

-p ssl这部分将信任范围限制在 TLS 连接内。如果省略此项,该证书将在 macOS 已知的所有用途中受到信任,包括代码签名,这远远超出了开发证书所需的范围。

如果想通过界面来完成此操作,请双击证书文件打开钥匙串访问,在系统钥匙串下找到该条目,打开它,展开信任部分,并将使用此证书时设置为始终信任。之后如需撤销,请从钥匙串访问中删除该条目。

Windows 证书存储

以管理员身份打开命令提示符(按Win + R,输入cmd,然后按Ctrl + Shift + Enter),并将证书添加到受信任的根证书颁发机构存储中:

certutil -addstore -f "Root" certificate.crt

或者,双击证书文件,选择安装证书,选择本地计算机,然后选择将所有的证书都放入下列存储,并浏览到受信任的根证书颁发机构。之后如需删除,请打开certmgr.msc并从该存储中删除该条目。

Linux ca-certificates

Debian 和 Ubuntu上,将证书复制到本地锚点目录中并重新构建证书包。文件必须保留.crt 扩展名,否则更新工具将忽略它:

sudo cp certificate.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

RHEL、CentOS、AlmaLinux、Rocky 和 Fedora上,路径有所不同:

sudo cp certificate.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract

Firefox 的特殊情况

Firefox 维护自己的信任存储,而不是使用操作系统的信任存储。在 Windows 和 macOS 上,它默认也会读取添加到操作系统存储中的根证书,因此上述步骤通常已经涵盖了这一情况。但在 Linux 上并非如此,所以证书需要直接导入 Firefox:打开设置,然后是隐私与安全,向下滚动到证书,点击查看证书,打开证书颁发机构标签,然后使用导入功能。

在完成上述任何更改后,请重启浏览器。浏览器会缓存证书判定结果,而一个过期的会话正是导入操作正确完成后警告仍然存在的常见原因。

何时不应使用自签名证书

切勿将其用于公众将访问的站点。每位访客都会看到一个全屏的安全警告,而那些依旧选择继续访问的人,实际上已经被训练成了会点击”继续”这一恰恰用来保护他们免受真实攻击的警告。此外,访客也无法区分您的自签名证书与攻击者伪造的证书,这正是浏览器不信任它们的根本原因。我们在关于自签名证书的风险的文章中详细讨论了这一点。

除了浏览器警告之外,自签名证书还无法满足许多实际要求。支付处理商、应用商店、带有证书绑定(certificate pinning)的移动应用,以及大多数合规制度都要求使用来自受认可 CA 的证书。对于任何面向公众的内容,请使用由受信任的证书颁发机构签发的证书,该证书需要通过CSR申请,并在签发前经过验证。证书上线后,请使用我们的SSL Checker确认安装情况。

立即订购 SSL 证书, 可节省 10% 的费用!

快速发行, 强大加密, 99.99% 的浏览器信任度, 专业支持和 25 天退款保证. 优惠券代码 SAVE10

龙飞行的详细图像
撰写人

经验丰富的内容撰稿人, 擅长 SSL 证书. 将复杂的网络安全主题转化为清晰, 引人入胜的内容. 通过有影响力的叙述, 为提高数字安全作出贡献.