Chrome等浏览器已默认将HTTP连接标记为不安全,Docker等工具也极力推荐使用HTTPS通信。在自建服务时,也有许多场景需要自己签发证书。本文粗略记述相关步骤。
另,需要对外开放的服务,可以尝试Let's Encrypt项目。
关于签发
名词解析
参考: OpenSSL自签发配置有多域名或ip地址的证书
- SSL:(Secure Socket Layer,安全套接字层)是在客户端和服务器之间建立一条SSL安全通道的安全协议
- TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性
- TLS的前身是SSL
- OpenSSL是TLS/SSL协议的开源实现,提供开发库和命令行程序
- HTTPS是HTTP的加密版,底层使用的加密协议是TLS
签发证书时的一些名词:
- FQDN: fully qualified domain name, 完全限定域名, 域名的一种,能指定其在域名系统 (DNS) 树状图下的一个确实位置。完整域名由主机名称与母域名两部分所组成,例如有一部服务器的本地主机名为myhost,而其母域名为example.com,那指向该服务器的完整域名就是myhost.example.com。
SAN: Subject Alternative Name, 主题备用名称, 是一项对X.509的扩展,它允许在安全证书中使用
subjectAltName
字段将多种值与证书关联,这些值被称为主题备用名称参考:What is the SSL Certificate Subject Alternative Name?
The Subject Alternative Name (SAN) is an extension to the X.509 specification that allows users to specify additional host names for a single SSL certificate. The use of the SAN extension is standard practice for SSL certificates, and it’s on its way to replacing the use of the common name.
- CSR: Certificate Signing Request, 凭证签发请求文件,一种包含凭证签发时所需的公钥及相关资讯的文件,不含私钥
- CRL: Certificate revocation list, 尚未到期就被证书颁发机构吊销的数字证书的名单
DN: distinguished name, 专有名称
证书持有人唯一的标识符, 这个名字在 Internet上应该是唯一的。DN由许多部分组成,看起来象这样:
CN=Bob Allen, OU=Total Network Security Division O=Network Associates, Inc. C=US
- CSR组成部分,CSR包含 information identifying the applicant and the applicant's public key that is used to verify the signature of the CSR - and the Distinguished Name (DN) that the certificate is for.
HTTPS原理
参考:什么是HTTPS?HTTPS原理
- 通信双方通信时使用对称加密,所需性能损耗少
- 对称加密使用的密钥由非对称加密传递,非对称加密的性能效率较低,但安全性更高
- 通信发起方A需要验证收到的公钥没有被篡改、替换,使用CA对服务提供方B的公钥认证,并颁发数字证书
- CA用自己的私钥加密B的公钥, 附带地区、机构等身份信息,生成数字证书,CA的公钥已经内置到A的系统中
- A用内置CA公钥解密B发送的数字证书,如果解密成功,则说明其中公钥为B认证过的公钥,否则证书内容没有完整性,通信不安全
数字证书
参考:证书颁发机构, X.509
证书实际是由证书签证机关(CA)签发的对用户的公钥的认证;内容包括:电子签证机关的信息、公钥用户信息、公钥、权威机构的签字和有效期等等。
证书格式
当前,证书的格式和验证方法普遍遵循X.509 国际标准。
X.509有多种常用的扩展名。不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。
.pem
– 隐私增强型电子邮件 Privacy-Enhanced Mail,DER编码的证书再进行Base64编码的数据存放在"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"之中.cer
,.crt
,.der
– 通常是DER Distinguished Encoding Rules二进制格式的,但Base64编码后也很常见。.p7b
,.p7c
– PKCS#7 SignedData structure without data, just certificate(s) or CRL(s).p12
– PKCS#12格式,包含证书的同时可能还有带密码保护的私钥.pfx
– PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS产生的PFX文件)
PKCS#7 是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用SignedData结构表述。 .P7C
文件是退化的SignedData结构,没有包括签名的数据。
PKCS#12 由PFX进化而来的用于交换公共的和私有的对象的标准格式。
PKCS 公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA信息安全公司所制定。
证书链
为防止根证书被污染,通常使用根证书签发的中介证书为客户作数字签署,得到终端实体证书。
中介证书的有效期会较根证书为短,并可能对不同类别的客户有不同的中介证书作分工。
终端实体证书不会用作签发其他证书。
多级证书间使用证书链传递信任信息
签发流程
- 流程
主要步骤
- 生成密钥对(key: private + public)
- 生成CSR,用私钥签名
- CA认证CSR(用私钥签名), 生成certificate
使用openssl自签证书链
基本操作
生成密钥
可以配置以下参数
- Key algorithm: openssl支持RSA, DSA, ECDSA类型的key,web server通常使用RSA
- Key size: 2048 bits RSA key被认为是安全的
Passphrase: optional, 可以让key安全存储、传输、备份,但使用时不方便,在生产环境中也不会过多增加安全性(存放在程序内存中,可以被取得)
- 支持AES-128, AES-192, AES-256,分别对应参数
-aes128
,-aes192
,-aes256
- 支持AES-128, AES-192, AES-256,分别对应参数
$ openssl genrsa -aes256 -out fd.key 2048
# 根据提示输入密码
创建CSR
CSR: Certificate Signing Request, a format request asking a CA to sign a certificate, 包含请求者的public key和一些身份信息
$ openssl req -new -key fd.key -out fd.csr
# 输出如下,交互式输入证书需要的信息
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Jiangsu
Locality Name (eg, city) []:Nanjing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:DafuTest
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:www.dafu.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
challenge password
, optional, 在吊销证书时,用于验证证书原来申请者身份的方式,很少有CA使用,不增加CSR安全性,建议留空
CSR配置文件
可以使用配置文件指定CSR必要信息,而避免交互式输入
$ opensll req -new -config fd.cnf -key fd.key -out fd.csr
配置文件如下:
[req]
prompt = no
distinguished_name = dn
req_extensions = ext
input_password = PASSPHRASE
[dn]
CN = www.feistyduck.com
emailAddress = webmaster@feistyduck.com
O = Feisty Duck Ltd
L = London
C = GB
[ext]
subjectAltName = DNS:www.feistyduck.com,DNS:feistyduck.com
自签证书
自己签发证书,而非向CA申请, 但需要另外添加信任
$ openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt
签发下级证书
参考:如何使用自签名 CA 和证书来保护个人在公网上的内容
用指定CA证书签发证书
$ openssl x509 -req -sha256 -in your-domain.com.csr -CA root.crt -CAkey root.key -CAcreateserial -out your-domain.com.crt -days 365 -extfile your-domain.com.ext
CAcreateserial
这个参数是比较有意思的,意思是如果证书没有 serial number 就创建一个,因为我们是签名,所以肯定会创建一个。序列号在这里的作用就是唯一标识一个证书,当有两个证书的时候,只有给这两个证书签名的 CA 和序列号都一样的情况下,我们才认为这两个证书是一致的。除了自定生成,还可以通过 -set_serial
手动指定一个序列号。
当使用 -CAcreateserial
参数之后,会自动创建一个和 CA 文件名相同的,但是后缀是 .srl
的文件。这里存储了上一次生成的序列号,每次调用的时候都会读取并 +1 。也就是说每一次生成的证书的序列号都比上一次的加了一。
校验证书
参考:Get your certificate chain right
校验根证书
$ openssl verify root.crt
该证书必须已被添加到系统中,且信任
校验二级证书
$ openssl verify -CAfile root.crt intermediate.crt
cert.pem: OK
校验三级证书
$ openssl verify -CAfile ca.pem \
-untrusted intermediate.cert.pem \
cert.pem
相关参数
-untrusted <file>
导入不受信任的证书(通常是intermedate CAs)来保证证书链顺利构建
-CAfile <file>
导入受信任CA证书
其他常用操作
查看密钥
密钥以PEM
格式存储,如下:
# cat fd.key
-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----
查看密钥内容:
$ openssl rsa -text -in fd.key
# 输出形如
RSA Private-Key: (2048 bit, 2 primes)
modulus:
[...]
publicExponent: 65537 (0x10001)
privateExponent:
[...]
prime1:
[...]
prime2:
[...]
exponent1:
[...]
exponent2:
[...]
coefficient:
[...]
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----
提取公钥
$ openssl rsa -in fd.key -pubout -out fd-public.key
# cat fd-public.key
-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----
查看CSR内容
$ openssl req -text -in fd.csr -noout
# 输出类似
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C = CN, ST = Jiangsu, L = Nanjing, O = DafuTest, OU = IT, CN = www.dafu.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
[...]
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: sha256WithRSAEncryption
[...]
签发过程
根证书
创建密钥
$ openssl genrsa -out root.key 2048
可以使用-aes256
参数加密,会提示输入密码
创建CSR
$ openssl req -new -key root.key -out root.csr
交互输入信息
签发证书
openssl x509 -req -days 365 -in root.csr -signkey root.key -out root.crt
中间证书
创建密钥
$ openssl genrsa -out mid.key 2048
创建CSR
$ openssl req -new -key mid.key -out mid.csr
签发证书
需要另外允许中间证书签发下级证书,可以通过extension实现
创建文件
mid.ext
basicConstraints = CA:TRUE
用根证书签发中间证书
openssl x509 -req -in mid.csr \ -CA root.crt -CAkey root.key \ -CAcreateserial \ -out mid.crt \ -days 365 \ -extfile mid.ext
末端证书
创建密钥
$ openssl genrsa -out server.key 2048
创建CSR
$ openssl req -new -key server.key -out server.csr
签发证书
需要指定SAN,目前许多服务通过SAN,代替CN,检查域名一致性
创建文件
server.ext
, 格式参考: x509v3_configsubjectAltName = @alt_names [alt_names] DNS.1 = your-domain.com DNS.2 = *.your-domain.com DNS.3 = *.api.your-domain.com IP = your-ip
用根证书签发中间证书
openssl x509 -req -in server.csr \ -CA mid.crt -CAkey mid.key \ -CAcreateserial \ -out server.crt \ -days 365 \ -extfile server.ext
openssl命令参考
记录openssl常用命令及参数
genrsa
generates an RSA private key
加密方式
-aes128, -aes192, -aes256, -aria128, -aria192, -aria256, -camellia128, -camellia192, -camellia256, -des, -des3, -idea
输出private key前用特定算法加密
-out <filename>
输出key到指定文件
rsa
The rsa command processes RSA keys. They can be converted between various forms and their components printed out.
-text
用encoded version 和 plain text形式打印various public/private key-noout
不输出encoded version的key-in <filename>
指定读取key的文件,如果没有指定,从standard input中获取-out <filename>
指定输出key的文件,如果没有指定,默认为standard output,输出文件名不能与-in
输入文件名相同-pubout
输出内容为public key,默认是private key。如果输入为public key,该选项自动指定加密方式
-aes128, -aes192, -aes256, -aria128, -aria192, -aria256, -camellia128, -camellia192, -camellia256, -des, -des3, -idea
输出private key前用特定算法加密
req
The req command primarily creates and processes certificate requests in PKCS#10 format. It can additionally create self signed certificates for use as root CAs for example.
-key <filename>
指定读取private key的文件,-new
生成a new certifacate,交互式输入证书相关信息,如果不使用该选项,会使用配置文件中信息生成private key$ openssl req -newkey rsa:2048 -keyout key.pem -out req.pem # 等价于 $ openssl genrsa -out key.pem 2038 $ openssl req -new -key key.pem -out req.pem
-newkey
creates a new certificate request and a new private key. 具体配置参数见文档-keyout
新创建的private key的文件名,默认按配置文件中指定filename-x509
outputs a self signed certificate instead of a certificate request- 通常用于生成测试证书或者 a self signed root CA.
- 需要的extensions通过配置文件指定
- 除非指定
set_serial
选项,否则使用一个large random number作为serial number - 如果使用
-in
选项指定CSR,将其转换为自签证书,否则生成一个新的CSR
-days
证书有效时间,正整数,默认30, 仅当指定-x509
时有效-text
文本形式打印证书-in <filename>
指定读取CSR文件,不指定指定从standard input获取。仅当新建request的选项(-new
,-newkey
)未指定时有效-noout
不输出加密格式的request
x509
多用途证书工具
- 展示证书信息
- 转换证书为各种格式
- 签发CSR
- 修改证书信任信息
常用参数:
-req
指定该选项时输入为CSR,不指定默输入为证书-days <arg>
证书有效时间,默认为30天,不能与-preserve_dates
同时出现-signkey
使用指定的private key签名输入文件如果输入的是证书,会改变以下内容:
- issuer name 设置为 subject name
- public key 变为指定值
- start date 设为当前时间
- end date 根据
-days
参数设置 - 除非指定
-clrext
选项,否则certificate extensions都不生效
如果输入是CSR
- 使用指定private key创建self signed certificate
- 证书subject name 同 CSR
-in
指定读取文件名,否则从standard input获取-out
指定输出文件名,否则输出至standard output
其他工具推荐
- FiloSottile/mkcert 一个开发环境快速配置本地信任证书的方便小工具
Nginx反选代理配置https
一般配置
server {
listen 8445 ssl;
keepalive_timeout 70;
# allow large uploads of files
client_max_body_size 5G;
ssl_certificate path_to_server_crt.crt;
ssl_certificate_key path_to_server_key.key; # key通过权限隔离
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8083/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "https";
}
}
证书链
假设根证书已经在客户主机添加信任,有中间证书bundle.crt
, 下级证书www.example.com.crt
生成证书链(注意顺序)
$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt
配置Nginx
server {
listen 443;
server_name www.example.com;
ssl on;
ssl_certificate www.example.com.chained.crt;
ssl_certificate_key www.example.com.key;
...
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。