我错过了什么吗?这是构建自签名证书的正确方法吗?
创建自签名证书很容易。您只需使用openssl req
命令。创建一个可供最多选择的客户端使用的客户端可能会很棘手,例如浏览器和命令行工具。
这很困难,因为浏览器有自己的一套要求,而且它们比IETF更严格。浏览器使用的要求记录在CA/浏览器论坛(请参阅下面的参考资料)。限制出现在两个关键领域:(1) 信任锚,和 (2) DNS 名称。
现代浏览器(如我们在 2014/2015 年使用的warez)需要一个链接回信任锚的证书,并且他们希望在证书中以特定方式显示 DNS 名称。浏览器正在积极反对自签名服务器证书。
某些浏览器并不完全可以轻松导入自签名服务器证书。事实上,你不能用一些浏览器,比如Android的浏览器。所以完整的解决方案是成为你自己的权威。
在没有成为您自己的权威的情况下,您必须获得正确的 DNS 名称才能使证书获得最大的成功机会。但我会鼓励你成为自己的权威。成为自己的权威很容易,它会回避所有信任问题(谁比自己更值得信任?)。
这可能不是您要找的网站!
该站点的安全证书不受信任!
这是因为浏览器使用预定义的信任锚列表来验证服务器证书。自签名证书不会链接回受信任的锚点。
避免这种情况的最佳方法是:
- 创建自己的权限(即成为CA)
- 为服务器创建证书签名请求 (CSR)
- 使用您的 CA 密钥签署服务器的 CSR
- 在服务器上安装服务器证书
- 在客户端安装 CA 证书
第 1 步 -创建您自己的授权只是意味着创建一个自签名证书CA: true
并正确使用密钥。这意味着Subject和Issuer是同一个实体,CA 在Basic Constraints中设置为 true (它也应该标记为关键),密钥用法是keyCertSign
and crlSign
(如果您使用 CRL),Subject Key Identifier (SKI) 是与授权密钥标识符(AKI) 相同。
要成为您自己的证书颁发机构,请参阅 *如何使用您的证书颁发机构签署证书签名请求?关于堆栈溢出。然后,将您的 CA 导入浏览器使用的信任库。
步骤 2 到 4 大致是您现在为面向公众的服务器所做的,当您征用像Startcom或CAcert这样的 CA 的服务时。步骤 1 和 5 可以让您避开第三方权威,并充当自己的权威(谁比自己更值得信任?)。
避免浏览器警告的下一个最佳方法是信任服务器的证书。但是有些浏览器,比如 Android 的默认浏览器,不允许你这样做。所以它永远不会在平台上工作。
浏览器(和其他类似的用户代理)不信任自签名证书的问题将成为物联网 (IoT) 中的一个大问题。例如,当您连接到恒温器或冰箱对其进行编程时会发生什么?答案是,就用户体验而言,没什么好说的。
W3C 的 WebAppSec 工作组开始研究这个问题。例如,请参阅提案:将 HTTP 标记为不安全。
如何使用 OpenSSL 创建自签名证书
下面的命令和配置文件创建一个自签名证书(它还向您展示了如何创建一个签名请求)。它们在一个方面与其他答案不同:用于自签名证书的 DNS 名称位于Subject Alternate Name (SAN)中,而不是Common Name (CN)中。
DNS 名称通过配置文件与行放在 SAN 中subjectAltName = @alternate_names
(无法通过命令行进行)。然后alternate_names
在配置文件中有一个部分(你应该调整它以适应你的口味):
[ alternate_names ]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = mail.example.com
DNS.4 = ftp.example.com
# Add these if you need them. But usually you don't want them or
# need them in production. You may need them for development.
# DNS.5 = localhost
# DNS.6 = localhost.localdomain
# IP.1 = 127.0.0.1
# IP.2 = ::1
将 DNS 名称放在 SAN 而不是 CN 中很重要,因为IETF和 CA/浏览器论坛都指定了这种做法。他们还指定不推荐使用 CN 中的 DNS 名称(但不禁止)。如果您将 DNS 名称放在 CN 中,则它必须包含在 CA/B 策略下的 SAN 中。所以你不能避免使用主题备用名称。
如果您不将 DNS 名称放在 SAN 中,则证书将无法在遵循 CA/浏览器论坛指南的浏览器和其他用户代理下验证。
相关:浏览器遵循 CA/浏览器论坛政策;而不是 IETF 政策。这就是使用 OpenSSL(通常遵循 IETF)创建的证书有时无法在浏览器下验证的原因之一(浏览器遵循 CA/B)。它们是不同的标准,它们有不同的发布政策和不同的验证要求。
创建一个自签名证书(注意添加-x509
选项):
openssl req -config example-com.conf -new -x509 -sha256 -newkey rsa:2048 -nodes \
-keyout example-com.key.pem -days 365 -out example-com.cert.pem
创建一个签名请求(注意缺少-x509
选项):
openssl req -config example-com.conf -new -sha256 -newkey rsa:2048 -nodes \
-keyout example-com.key.pem -days 365 -out example-com.req.pem
打印自签名证书:
openssl x509 -in example-com.cert.pem -text -noout
打印签名请求:
openssl req -in example-com.req.pem -text -noout
配置文件(通过-config
选项传递)
[ req ]
default_bits = 2048
default_keyfile = server-key.pem
distinguished_name = subject
req_extensions = req_ext
x509_extensions = x509_ext
string_mask = utf8only
# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
# Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
[ subject ]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = NY
localityName = Locality Name (eg, city)
localityName_default = New York
organizationName = Organization Name (eg, company)
organizationName_default = Example, LLC
# Use a friendly name here because it's presented to the user. The server's DNS
# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
# by both IETF and CA/Browser Forums. If you place a DNS name here, then you
# must include the DNS name in the SAN too (otherwise, Chrome and others that
# strictly follow the CA/Browser Baseline Requirements will fail).
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Example Company
emailAddress = Email Address
emailAddress_default = test@example.com
# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
[ x509_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
# You only need digitalSignature below. *If* you don't allow
# RSA Key transport (i.e., you use ephemeral cipher suites), then
# omit keyEncipherment because that's key transport.
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# In either case, you probably only need serverAuth.
# extendedKeyUsage = serverAuth, clientAuth
# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
[ req_ext ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
# RFC 5280, Section 4.2.1.12 makes EKU optional
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
# In either case, you probably only need serverAuth.
# extendedKeyUsage = serverAuth, clientAuth
[ alternate_names ]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = mail.example.com
DNS.4 = ftp.example.com
# Add these if you need them. But usually you don't want them or
# need them in production. You may need them for development.
# DNS.5 = localhost
# DNS.6 = localhost.localdomain
# DNS.7 = 127.0.0.1
# IPv6 localhost
# DNS.8 = ::1
您可能需要对 Chrome 执行以下操作。否则Chrome 可能会抱怨Common Name is invalid ( ERR_CERT_COMMON_NAME_INVALID
)。在这种情况下,我不确定 SAN 中的 IP 地址和 CN 之间的关系是什么。
# IPv4 localhost
# IP.1 = 127.0.0.1
# IPv6 localhost
# IP.2 = ::1
关于在 X.509/PKIX 证书中处理 DNS 名称还有其他规则。有关规则,请参阅这些文档:
列出了 RFC 6797 和 RFC 7469,因为它们比其他 RFC 和 CA/B 文档更严格。RFC 6797 和 7469也不允许IP 地址。