创建自签名的 SSL 证书
SSL 证书是一种数字证书,用于在客户端和服务器之间建立安全的加密连接,确保数据在传输过程中不被窃取或篡改。在互联网上,通常由权威的证书颁发机构(CA)给用户颁发证书。通常可以利用云服务厂商提供的证书管理服务获取证书(可能是付费的),也可以向 Let's Encrypt 这个免费、自动化且开放的证书颁发机构申请证书。除此之外,对于内部应用,还可以自行创建证书。本文介绍创建自签名的SSL证书的方式。
任务 🔗
给 my.internal
域名创建自签名的证书。
工具 🔗
本文使用 openssl
的命令行工具创建证书。MacOS 和大部分的 Linux 发行版,应该都内置了这个工具。
步骤 🔗
创建文件结构 🔗
创建两个目录:ca
和 my.internal
分别保存 CA 和 my.internal
的相关文件:
mkdir ca && make my.internal
创建根证书 🔗
根证书(Root certificate)是信任的源头。在数字证书体系中,它处于最顶层的位置。浏览器、操作系统等软件在出厂时会预装一些受信任的根证书。当用户访问一个使用了由受信任的根证书颁发机构(CA)所颁发的 SSL 证书的网站时,软件会通过信任链的验证机制,从该网站的证书追溯到根证书,如果根证书是受信任的,那么就认为该网站的证书也是可信的,从而建立起安全的连接。
以下操作在 ca
目录下操作。
创建根证书的密钥 🔗
openssl genrsa -des3 -out ca.key 2048
创建证书配置 🔗
创建证书配置文件 ca.conf
,内容如下:
[ca]
default_ca = CA_default
[CA_default]
default_days = 3650
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = (此处写国家,比如CN)
ST = (此处填写省)
L = (此处填写城市)
O = (此处填写 Orgnisation)
OU = (此处填写 Orgnisation Unit)
CN = (此处填写证书名称,比如MyRoot CA)
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
创建根证书 🔗
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -config ca.conf
生成的根证书文件为 ca.crt
。
颁发证书 🔗
以下操作在 my.internal
目录下操作。
创建密钥 🔗
一些 HTTP 服务器无法使用有密码保护的私密。因此在创建密钥时,直接生成 RSA 密钥:
openssl genrsa -out private_key.pem 2048
创建证书配置 🔗
与CA证书类似,创建配置文件 openssl.conf
,内容如下:
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = (此处写国家,比如CN)
ST = (此处填写省)
L = (此处填写城市)
O = (此处填写 Orgnisation)
OU = (此处填写 Orgnisation Unit)
CN = my.internal
[v3_req]
basicConstraints = CA:false
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.0 = localhost
DNS.1 = my.internal
创建证书签名请求 🔗
接下来生成“证书签名请求”,即 Certificate Signing Request (CSR)。
openssl req -new -key private_key.pem -out csr.pem -config openssl.conf
对证书进行签名 🔗
使用根证书、根证书密钥,对证书签名请求进行签名:
openssl x509 -req -days 365 -in csr.pem -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out certificate.pem
生成的证书文件为 certificate.pem
。
在 HTTP 服务器部署证书 🔗
将 my.internal
目录下的 certificate.pem
和 private_key.pem
上传到 HTTP 服务器。以 Nginx 为例,将它们上传到 /etc/nginx/conf.d/my.internal
目录下(注意设定合适的文件权限,或者文件所有者)。假定后端的服务位于本机的 8000
端口。那么服务器配置如下(可放在 /etc/nginx/conf.d/my.internal.conf
文件中):
server {
server_name my.internal;
listen 443 ssl;
ssl_certificate /etc/nginx/conf.d/my.internal/certificate.pem;
ssl_certificate_key /etc/nginx/conf.d/my.internal/private_key.pem;
location / {
proxy_pass http://localhost:8000;
}
}
在客户端电脑上安装根证书 🔗
此时使用 curl
访问站点:
curl -H "Host: 127.0.0.1" https://my.internal
但curl
会给出证书错误的消息。这是因为系统还没有“信任”这个证书。为此,可以让系统“信任”根证书,那么就会信任这个根证书颁发的所有证书。
在 macOS 上,可以打开 Keychain Access
(密钥串访问) 程序。在 login
或 System
密钥串中,选择 Certificates
选项卡,然后将根证书文件(即 ca/ca.cert
)拖动到窗口中,然后双击根证书项,打开详情后,点击 Trust
,将 When using this certificate
设置为 Always Trust
。如图所示:
此时,回到密钥串列表里,如下图所示:
验证配置 🔗
使用 curl
访问站点:
curl -H "Host: 127.0.0.1" https://my.internal
确保没有证书错误。
使用浏览器访问站点 🔗
由于 my.internal
是内部域名,因此需要修改本地 DNS 才可以访问。为此,修改 /etc/hosts
,添加记录:
127.0.0.1 my.internal
然后使用浏览器访问 https://my.internal。此时,Chrome 和 Firefox 浏览器依然会将站点标记为Not Secure
(不安全)。
其中, Firefox 给出的提示是:
Someone could be trying to impersonate the site and you should not continue.
Websites prove their identity via certificates. Firefox does not trust my.internal because its certificate issuer is unknown, the certificate is self-signed, or the server is not sending the correct intermediate certificates.
Error code: SEC_ERROR_UNKNOWN_ISSUER
View Certificate
点击 Accept the Risk and Continue
才可以继续访问站点。