总结下来,其实生成证书就两句话:
1 2 3 4 5 6 7 8 9 |
DOMAIN='www.example.com' SUBJECT="/C=US/ST=Mars/L=iTranswarp/O=iTranswarp/OU=iTranswarp/CN=$DOMAIN" openssl req -nodes -new -subj $SUBJECT -keyout $DOMAIN.key -out $DOMAIN.csr printf "subjectAltName=DNS:localhost,IP:192.168.1.1" | \ openssl x509 -req -sha256 -days 3650 -in $DOMAIN.csr \ -signkey $DOMAIN.key -out $DOMAIN.crt \ -extfile /dev/stdin |
———————————————-
有一个shell脚本来自动生成证书:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#!/bin/sh # create self-signed server certificate: read -p "Enter your domain [www.example.com]: " DOMAIN echo "Create server key..." openssl genrsa -des3 -out $DOMAIN.key 1024 echo "Create server certificate signing request..." SUBJECT="/C=US/ST=Mars/L=iTranswarp/O=iTranswarp/OU=iTranswarp/CN=$DOMAIN" openssl req -new -subj $SUBJECT -key $DOMAIN.key -out $DOMAIN.csr echo "Remove password..." mv $DOMAIN.key $DOMAIN.origin.key openssl rsa -in $DOMAIN.origin.key -out $DOMAIN.key echo "Sign SSL certificate..." openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.crt echo "TODO:" echo "Copy $DOMAIN.crt to /etc/nginx/ssl/$DOMAIN.crt" echo "Copy $DOMAIN.key to /etc/nginx/ssl/$DOMAIN.key" echo "Add configuration in nginx:" echo "server {" echo " ..." echo " listen 443 ssl;" echo " ssl_certificate /etc/nginx/ssl/$DOMAIN.crt;" echo " ssl_certificate_key /etc/nginx/ssl/$DOMAIN.key;" echo "}" |
另一个脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#!/bin/sh domain='gpaas.yyuap.com' # 生成证书和key的对应文件名 ca_file=${domain}.ca key_file=${domain}.key cert_file=${domain}.crt printf "[req] default_bits = 4096 default_md = sha256 prompt = no encrypt_key = no string_mask = utf8only distinguished_name = cert_distinguished_name req_extensions = req_x509v3_extensions # 将下面的信息替换成你的信息 [ cert_distinguished_name ] C = CN ST = GD L = GZ O = yyuap OU = yyuap CN = gpaas.yyuap.com [req_x509v3_extensions] basicConstraints = critical,CA:true subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer keyUsage = critical,digitalSignature,keyCertSign,cRLSign #,keyEncipherment extendedKeyUsage = critical,serverAuth #, clientAuth subjectAltName=@alt_names # 将下面的信息替换成你的信息, 如果无需绑定域名或IP, 可以将其多余删除 [alt_names] DNS.1 = *.yyuap.com IP.1 = 172.20.47.38 IP.2 = 127.0.0.1 " >$ca_file openssl ecparam -out $key_file -name prime256v1 -genkey openssl req -new -sha256 -x509 -days 7300 -config $ca_file -extensions req_x509v3_extensions -key $key_file -out $cert_file openssl x509 -in $cert_file -serial -noout openssl x509 -noout -text -in "$domain-cert.pem" echo -e "\e[1m\e[34m基于openssl verify校验证书可用性:\e[0m" # 返回ok字样代表自签名证书是有效的. openssl verify -verbose -CAfile $cert_file $cert_file echo -e "\e[1m\e[34m基于openssl s_server校验证书可用性:\e[0m" openssl s_server -cert $cert_file -key $key_file -CAfile $cert_file -Verify 3 -accept 4430 -www & openssl_pid=$! # 测试证书有效性, 127.0.0.1可以改成alt_names中你想测试的域名或IP, 前提是被测试的域名需要被正确解析到本机. # 返回Verify return code: 0 (ok)代表自签名证书是有效的. echo 'GET /HTTP/1.1' | openssl s_client -connect 127.0.0.1:4430 -cert $cert_file -key $key_file -CAfile $cert_file kill ${openssl_pid} |
参考:https://www.fullstackmemo.com/2018/05/10/openssl-gen-https-self-signed-cer/
nginx配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
server { listen 80; server_name xxx.com gpaas.xxx.com; #return 301 https://$server_name$request_uri; #rewrite ^/(.*) https://$server_name$request_uri? permanent; # 80端口全部重定向到 https if ($scheme = http){ return 301 https://$host$request_uri; } } #启用 https, 使用 http/2 协议, nginx 1.9.11 启用 http/2 会有bug, 已在 1.9.12 版本中修复. listen 443 ssl http2; charset utf-8; server_name xxx.com gpaas.xxx.com; #告诉浏览器当前页面禁止被frame add_header X-Frame-Options DENY; #告诉浏览器不要猜测mime类型 add_header X-Content-Type-Options nosniff; #证书路径 ssl_certificate cert/meaninglive.com/full_chain.pem; #私钥路径 ssl_certificate_key cert/meaninglive.com/private.key; #安全链接可选的加密协议 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #可选的加密算法,顺序很重要,越靠前的优先级越高. ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; #在 SSLv3 或 TLSv1 握手过程一般使用客户端的首选算法,如果启用下面的配置,则会使用服务器端的首选算法. ssl_prefer_server_ciphers on; #储存SSL会话的缓存类型和大小 ssl_session_cache shared:SSL:10m; #缓存有效期 ssl_session_timeout 60m; |
—————证书知识补充——————————-
自签名证书 + Nginx 实现 HTTP 升级 HTTPS
很多内网平台在开发时候并没有考虑 HTTPS,想要从 HTTP 升级到 HTTPS 一般有两种方法:一种是更新所有相关前后端代码;另一种是基本不改变代码,用 Nginx 把 HTTPS 反向代理到 HTTP 接口。第一种方法工作量有点大,本文介绍下第二种方法,当然首先要做的是生成自签名证书。
准备工作
内网 环境受影响的是 软件安装升级 和 证书申请,所以需要 制作本地 yum 和 自签名证书,自签名证书稍后讲,制作本地 yum 库可参考链接内容, HTTPS 和 CA 基础知识 查看这里 。
- 制作本地 yum 库,为了自动处理软件之间的依赖关系,一般都会用 yum 等软件包管理器来安装更新软件,默认 yum 是从互联网获取各种软件包的,内网环境就需要制作本地 yum 库。
- 自签名证书,证书是否安全依赖于 CA 机构的认证,虽然有很多免费证书可以申请,但是内网 IP 是无法申请的,而且内网地址也没必要花钱做 CA 认证,这就需要我们制作自签名证书。
自签名证书过程
比如在内网的测试环境中,为了验证 HTTPS 下的一些问题,我们没必要申请昂贵的证书,这个时候就可以自签名一个证书,自签名证书步骤如下:
- 创建根证书(Root CA)。
- 生成私钥(.key),私钥只能自己拥有;
- 生成证书请求文件(.csr),实际上就是把自身一些信息(国家、机构、域名、邮箱等)用第一步的私钥加密。
- 自签名证书(.crt),用第一步的私钥给第二步的证书请求文件签名,根证书肯定是自签名的,CA 机构给自己发的证书。
- 创建中间证书(Intermediate CA),用根证书给中间证书签名,中间证书再给用户签名,提高安全性。
- 生成私钥(.key),要保证私钥只有自己拥有;
- 生成证书请求文件(.csr),实际上就是把自身一些信息(国家、机构、域名、邮箱等)用自己的私钥加密产生的文件。
- 根证书签名(.crt),用根证书的私钥给中间证书的证书请求文件签名,签名之后意味着 CA 机构信任中间证书。
- 创建用户证书,用中间证书给用户签名,最终形成 用户证书–>中间证书–>根证书 的证书链,而浏览器信任根证书发布机构。这里的用户一般指服务提供商,如百度、阿里、腾讯等,他们的证书需要 CA 机构的签名,当然在他们看来我们也是用户,但是绝大部分环境都是单向 https 认证,我们不需要提供证书。
- 生成私钥(.key),要保证私钥只有用户自己拥有;
- 生成证书请求文件(.csr),由用户的私钥和用户自身的信息(国家、机构、域名、邮箱等)生成。其中用户的公钥和用户的信息是明文保存在证书请求文件中,而用户私钥的作用是对用户公钥及用户自身信息做签名,私钥不包含在证书请求中;
- 中间证书签名(.crt),用中间证书的私钥给用户证书的证书请求文件签名,签名之后意味着中间证书信任用户证书。
自签名证书步骤
先一步一步来,掌握原理后可以 两条命令生成自签名证书 ,【传送门】 在这里。想仔细了解的话,先看看创建证书过程中用到的 openssl
命令:
命令 | 功能 | 备注 |
---|---|---|
req | 生成证书请求文件和自签名证书 | 创建和处理 PKCS#10 格式的证书 |
x509 | X.509 证书管理。 显示证书信息、转换证书格式、签名证书请求及改变证书信任设置 |
证书工具 |
ca | 签发证书请求和生成CRL,维护一个已签发证书状态的文本数据库 | 证书中心 |
verify | X.509证书验证 | 证书验证 |
在 CentOS 系统下 openssl
配置文件的路径在 /etc/pki/tls/openssl.cnf
,req
和 ca
需要读取配置文件里面的很多设置,但 x509
不读取配置文件,一切配置都由 x509 自行提供。req
下有个 [-x509]
参数,[x509]
下也有一个[-req]
参数,不是一个东西,不要混淆。
创建根证书
1. 生成私钥
1 |
$ openssl genrsa -out ca.key 2048 |
genrsa
有很多参数,常用的有:
[-out]
,指定生成文件名;[-des|-des3|-idea]
,采用什么加密算法来加密我们的密钥,使用其中任一参数,在生成密钥的过程都会要求输入密码,缺省情况无需输入密码,我们这里就没有加密;[numbits]
,指明产生参数的长度。必须是最后一个参数。我们这里是 2048,缺省则产生 512bit 长的参数(不过我看配置文件默认好像也是2048?)。
2. 生成证书请求文件
这个过程会要求输入很多信息如国家、城市、组织信息等,其中 Common Name (eg, your name or your server's hostname)
是 必填项 ,可以是域名或者 IP,其他都可以回车跳过,但是这样的话在签名证书时候会报错,下一章详述,不过自签名证书不影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ openssl req -new -key ca.key -out ca.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) [XX]: State or Province Name (full name) []: Locality Name (eg, city) [Default City]: Organization Name (eg, company) [Default Company Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:myca Email Address []: An optional company name []: |
[-new]
,生成证书请求文件,它会提示用户关于一些字段的值。可以通过openssl.cnf
来查看默认会询问那些字段,最大/小长度限制等,如果[-key]
没有指定,则会按照默认配置文件生成新的私钥>;[-key]
,指定已有的密钥文件;[-out]
,指定生成文件名。
Common Name 是必填项,如果是根证书 Common Name 可以写公司名、字母缩写等,我上面用的 myca,但如果是用于服务器的证书,这里必须用域名或者 IP 。
3. 生成自签名证书
1 |
$ openssl req -x509 -days 3650 -key ca.key -in ca.csr -out ca.crt |
或者
1 2 3 |
$ openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -out ca.crt Signature ok subject=/C=XX/L=Default City/0=Default Company Ltd/CN=myca |
[-x509]
,req
中的[-x509]
表示生成一个自签名的证书,而不是一个证书请求;[-req]
,x509
中的[-req]
表示 in 后面的输入文件为证书请求文件,默认是证书文件;[-signkey]
,用于提供自签名时的私钥文件。
4. 查看证书信息
查看证书请求(csr)信息
1 |
$ openssl req -in ca.csr -text -verify -noout |
查看证书(crt)信息
1 |
openssl x509 -in ca.crt -text -noout |
x509
用于查看证书(crt)的信息,req
用于查看证书请求(csr)的信息,当然证书和证书请求并不是靠后缀来区分的。
[-text]
,以 text 格式输出证书请求;[-noout]
,不输出证书请求中的编码版本信息;[-verify]
,校验请求文件的签名信息。
证书信息包含:
- 数字签名(Signature Algorithm)
- 有效时间(Validity)
- 主体(Issuer)
- 公钥(Public Key)
- X509v3 扩展,openssl config 中配置了 v3_ca,所以会生成此项
创建用户证书
1. 生成私钥
1 |
$ openssl genrsa -out server.key 2048 |
2. 生成证书请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ openssl req -new -key server.key -out server.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) [XX]: State or Province Name (full name) []: Locality Name (eg, city) [Default City]: Organization Name (eg, company) [Default Company Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:www.myweb.com Email Address []: An optional company name []: |
其中 Common Name (eg, your name or your server's hostname)
是 必填项 ,要填写自己的域名或者 IP,其他都可以回车跳过。
问题:
如果 Common Name
和自己的域名或者 IP 不符,会报错 NET::ERR_CERT_INVALID ,但如果是用于根证书,Common Name
甚至可以写公司名、字母缩写等字符串。
3. 生成证书(根证书对用户的证书请求签名,最终生成用户证书)
1 |
$ openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key |
生成私钥和证书请求这两步,和根证书的操作基本一样,第三步根证书是用 [-x509]
自签名,而这里是用根证书给用户的证书请求签名,用了 [ca]
命令:
[-cert]
,指定 CA 证书;[-keyfile]
,指定私钥。
问题 1:
报错 The mandatory stateOrProvinceName field was missing。
这是因为在生成证书请求 server.csr
时候只填写了 Common Name
这一项,而配置文件 openssl.cnf
中配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy [ policy_anything ] countryName = optional stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional |
match
意味着要匹配才行,而我们都没填所以会报错,解决办法就是使用参数 [-policy]
,从配置文件中可以看到 policy_anything
其实就是把 match
变成了 optional
,命令如下:
1 |
$ openssl ca -policy policy_anything -in server.csr -out server.crt -cert ca.crt -keyfile ca.key |
问题 2:
报错 Using configuration from /etc/pki/tls/openssl.cnf
I am unable to access the /etc/pki/CA/newcerts directory
/etc/pki/CA/index.txt: No such file or directory
unable to open ‘/etc/pki/CA/index.txt’
有可能是权限问题,也有可能是缺少必要文件,证书生成过程中主要会用到如下文件:
- /etc/pki/tls/openssl.cnf
- /etc/pki/CA/newcerts
- /etc/pki/CA/index.txt
- /etc/pki/CA/serial
openssl ca 方式解决
openssl.cnf
是配置文件,index.txt
和 serial
分别是证书索引数据库文件和证书序列号文件,创建这些文件即可:
1 2 3 |
$ touch CA/index.txt $ touch CA/serial $ echo "01" > CA/serial |
现在继续生成证书:
1 2 3 |
$ openssl ca -policy policy_anything -in server.csr \ -out server.crt -cert ca.crt -keyfile ca.key \ -config myopenssl.cnf |
openssl x509 方式解决
也可以使用 x509
工具生成证书,因为它默认不使用 openssl.cnf
所以没有上面那么多问题:
1 2 |
$ openssl x509 -req -in server.csr -CA ca.crt \ -CAkey ca.key -out server.crt -CAcreateserial |
[-req]
,使用该参数时,[-in]
后面将要使用证书请求文件,不指定该参数时,x509 工具默认以证书文件做为输入;[-CA]
,指定根证书;[-CAkey]
,指定根证书私钥;[-CAcreateserial]
,如果 CA 使用的序列号文件不存在将自动创建。
问题 3:
报错 failed to update database TXT_DB error number 2。
CommonName
冲突造成的,应该是目前签名的证书与另一个证书的 CommonName
重复造成,删除 index.txt
文件即可。
4. 查看、校验证书
查看证书请求(csr)信息
1 |
$ openssl req -in server.crt -text -verify -noout |
查看证书(crt)信息
1 |
$ openssl x509 -in server.crt -text -noout |
5. 验证证书有效性
verify 命令对证书的有效性进行验证,verify 指令会沿着证书链一直向上验证,直到一个自签名的 CA:
1 2 |
$ openssl verify -CAfile ca.crt server.crt server.crt: OK |
[-CAfile]
,指定 CA 的证书文件,这个文件里可能不只包含一个证书。如果需要对证书链进行验证,指定的文件中应包含所有的证书,需要把证书链中的证书都包含,证书文件都是文本文件,简单地使用 cat
命令就可以进行连接。
6. 生成 pem 格式证书(可选)
有时需要用到 pem 格式的证书,可以用以下方式合并证书文件(crt)和私钥文件(key)来生成:
1 |
$cat server.crt server.key > server.pem |
现在把生成的私钥 server.key
和证书 server.crt
配置到 nginx 就已经可以使用了,但是还有些问题,比如最直观的的,Chrome 浏览器会提醒“您的连接不是私密连接”,然后显示一个红色叉号。
Chrome 下的问题
这三个警告的原因分别是:
- 网站的证书链中存在 SHA-1 签名算法,改为 SHA256 即可。
- 网站证书的 Subject Alternative Nam 扩展中没有域名或者 IP,Chrome 是根据证书中的 SAN 来判断访问的域名和证书中的域名是否一致,所以图 1 中提示“此服务器无法证明其所在网域是xxx”,添加 SAN 扩展并指定正确的域名或者 IP 即可。
- 网站证书不可信,浏览器导入根证书即可。
解决办法
关于第一个问题 SH1 签名算法
因为浏览器验证的是服务器证书,虽然第一个警告提示证书链中存在在 SHA-1 签名算法,但我推测与根证书自签名的算法无关,应该指的是中间证书和服务器证书的签名算法,因为我查看了本机“受信任的根证书机构”,很多证书也是用的 SHA-1 签名算法,这个用 [ca]
的 [-md]
参数指定签名算法为 sha256 即可。
关于第三个问题证书不可信
证书不可信,导入根证书即可,其实自签名的根证书可以直接用作服务端证书,下一章我们会说,这样最明显的缺点就是你又上线了一个不同域名的网站,那还要重新生成一个自签名证书,重新导入一次。但是根证书只用于签名的话,不管多少域名多少网站,只要导入根证书,用这个根证书签名的网站证书就都是可信的,不需要一次次导入。
关于第二个问题 SAN 扩展
重点说一下,我们在生成证书请求时候填过一个 Common Name
,以前 Chrome 是根据证书的 CN(Common Name)来匹配域名或 IP,但是现在改为用 SAN(Subject Alternative Name)扩展来匹配域名或 IP 了(但服务器证书的 Common Name 依然需要和自己的域名或者 IP 匹配),所以 需要在签名时候指定 SAN 扩展 ,其实生成证书请求和生成证书这两个阶段都能选择添加 SAN 扩展,我分别尝试仅在证书请求阶段或者签名阶段添加 SAN 扩展,签名阶段添加才会有效。
openssl ca 方式解决
添加 SAN 扩展需要修改配置文件:
- 取消
/etc/pki/tls/openssl.cnf
中[req]
节点下这句注释req_extensions= v3_req
,如果想使用自定义的配置文件,看 传送门 。 - 在
[v3_req ]
节点下新增属性subjectAltName = @alt_names
。 - 新增如下节点,如果没有 DNS 只填写 IP 即可:
1234[ alt_names ]DNS.1 = localhostDNS.1 = www.abc.comIP.1 = 192.168.1.1
- 用如下命令签名证书:
123$ openssl ca -days 3650 -md sha256 -in server.csr \-out server.crt -cert ca.crt -keyfile ca.key -policy \policy_anything -config openssl.cnf -extensions v3_req
[-md]
,指定签名算法;[-config]
,指定配置文件;[-extensions]
,指定证书扩展。
openssl x509 方式解决
1 2 3 |
$ openssl x509 -req -sha256 -days 3650 -in server.csr \ -CA ca.crt -CAkey ca.key -out server.crt -CAcreateserial \ -extfile openssl.cnf -extensions v3_req |
根证书导入浏览器后,上面问题就全部解决了。
自定义配置文件(可选)
CentOS 下 openssl
默认使用的配置文件是 /etc/pki/tls/openssl.cnf
,不过生成证书的过程中不仅仅依赖这一个文件,自定义配置文件还需要生成其他一些必备的文件:
1 2 3 4 5 |
$ mkdir -p CA/newcerts $ cp /etc/pki/tls/openssl.cnf myopenssl.cnf $ touch CA/index.txt $ touch CA/serial $ echo "01" > CA/serial |
index.txt
和 serial
分别是证书索引数据库文件和证书序列号文件,还需要修改 /etc/pki/tls/openssl.cnf
中 [ CA_default ]
下的 dir
为 dir = ./CA
,这样就把根路径指定到了当前目录下的 CA
文件夹,接下来还需要配置 SAN 扩展,看这里 传送门,现在我们可以使用自己的配置文件来生成证书:
1 2 3 |
$ openssl ca -policy policy_anything -in server.csr \ -out server.crt -cert ca.crt -keyfile ca.key \ -config myopenssl.cnf |
自签名证书总结
修改配置文件
sudo vim /etc/pki/tls/openssl.cnf
,确保以下信息存在:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
... ... [ req ] ... req_extensions= v3_req [ v3_req ] basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost DNS.1 = www.abc.com IP.1 = 192.168.1.1 ... ... |
主要是针对 SAN 扩展的修改,可以参考配合上一章内容,点 传送门。
根证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 生成根证书私钥 $ openssl genrsa -out ca.key 2048 # 生成根证书请求文件 $ openssl req -new -key ca.key -out ca.csr # 生成根证书(自签名) $ openssl req -x509 -days 3650 -key ca.key -in ca.csr -out ca.crt # 生成根证书(效果等同上一句) $ openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -out ca.crt # 查看证书请求文件 $ openssl req -in ca.csr -text -verify -noout # 查看证书 $ openssl x509 -in ca.crt -text -noout |
用户证书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 生成服务端私钥 $ openssl genrsa -out server.key 2048 # 生成服务端证书请求文件 $ openssl req -new -key server.key -out server.csr # 生成服务端证书(根证书给服务端证书签名) $ openssl ca -days 3650 -md sha256 -in server.csr \ -out server.crt -cert ca.crt -keyfile ca.key -policy \ policy_anything -config openssl.cnf -extensions v3_req # 生成服务端证书(效果等同上一句) $ openssl x509 -req -sha256 -days 3650 -in server.csr \ -CA ca.crt -CAkey ca.key -out server.crt -CAcreateserial \ -extfile openssl.cnf -extensions v3_req # 查看服务端证书请求信息 $ openssl req -in server.crt -text -verify -noout # 查看服务端证书信息 $ openssl x509 -in server.crt -text -noout |
懒人版自签名证书
以上我们都是先生根成私钥 ca.key
和根证书 ca.crt
,再用 ca.key
和 ca.crt
给用户证书请求 server.csr
签名,其实最简单的方法是直接使用自签名的根证书作为网站的证书,以下如果遇到问题请参考 创建用户证书 和 Chrome-下的问题 章节的细节。
一句话生成证书
- 需要先配置好 openssl.cnf 文件,其实就是配置一下 SAN 扩展,配置方法点 传送门,也可以自定义配置文件,详细点 传送门。
- 生成证书
123$ openssl req -x509 -nodes -sha256 -newkey \rsa:2048 -keyout server.key -out server.crt \-config openssl.cnf -extensions v3_req
[-nodes]
,如果生成了私钥,则不加密,该参数可以避免每次重启 nginx 都要输一次密码。[-sha256]
,指定签名算法;[-newkey]
,建立一个新的证书请求和一个新的 private key,后面需要指定秘钥位数比如rsa:1024
,生成的密钥名称由[-keyout]
指定;[-keyout]
,指定生成秘钥的名称;[-config]
,指定配置文件;[-extensions]
,指定扩展。
两句话生成证书
X509 工具优点是 不依赖配置文件 openssl.cnf,但仍然需要先提供 SAN 扩展信息 。X509 工具无法自己生成证书请求文件,所以需要先用 openssl req
生成证书请求,虽然没用 genrsa
但还是生成了私钥,可能是 openssl req
使用了默认配置:
1 2 3 4 |
$ openssl req -nodes -new -keyout server.key -out server.csr $ openssl x509 -req -sha256 -days 3650 -in server.csr \ -signkey server.key -out server.crt \ -extfile <(printf "subjectAltName=DNS:localhost,IP:192.168.1.1") |
[-nodes]
, 密钥文件不加密。不加此参数会要求 “Enter PEM pass phrase:” ,可能这种方式生成的 key 和openssl genrsa -des3
差不多;[-signkey]
,用于提供自签名时的私钥文件;[-extfile]
,指定签名时包含要添加到证书中的扩展项的文件,自签名时候可以这样使用,根证书签名时候还是要用配置文件,直接这样用报错x509 error loading the config file /dev/fd/63
,原因未知。
注意:
上面是 X509 工具生成自签名证书的命令,如果是通过 X509 工具用根证书给用户证书签名,是不可以直接在命令中指定 SAN 扩展的,会报错 x509 error loading the config file /dev/fd/63,原因未知,但是可以用下面方法来签名:
- 配置 SAN 扩展,新建配置文件
v3.ext
如下:
1234567891011$ vim v3.extauthorityKeyIdentifier=keyid,issuerbasicConstraints=CA:FALSEkeyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEnciphermentsubjectAltName = @alt_names[alt_names]IP.1 = 192.168.1.1DNS.1 = localhost#DNS.2 = www.myweb.com
- 生成证书
123$ openssl x509 -req -sha256 -days 3650 -in server.csr \-CA ca.crt -CAkey ca.key -out server.crt \-extfile v3_ext -CAcreateserial
Nginx 配置
静态资源的配置很简单,Nginx 上开启 ssl 配置后就可以了,但是动态资源要和后端做交互,在发送 ajax 请求或者要获取 http 资源的时候,就会造成 https 请求无法请求 http 后端的接口,有两种解决方法:
- 将后端的项目添加 https 支持,所有前端的 http 请求都要改成 https ,但这样工作量较大。
- 后端接口依然是 http 请求,但是客户端到 Nginx 用 https,请求后端接口时候,用 Nginx 反向代理到 http 接口上。
nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
... ... upstream myweb { server 192.168.1.11:7000; server 192.168.1.12:8000; keepalived 18; } server { listen 80; server_name www.xxx.com; # 域名,或者 IP 比如 192.168.2.33 rewrite ^/(.*) https://$server_name$request_uri? permanent; # 80端口全部重定向到 https #if ($scheme = http){ # return 301 https://$host$request_uri; #} } server { listen 443; server_name www.xxx.com; # 域名,或者 IP 比如 192.168.2.33 ssl on; ssl_certificate myca/server.crt; ssl_certificate_key myca/server.key; ssl_session_timeout 5m; ssl_prefer_server_ciphers on; ssl_ciphers HIGH:!aNULL:!MD5; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; location / { root /var/www/html; # 静态资源路径地址 index index.html index.htm; } location /api { proxy_pass http://myweb; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-Ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; } } ... ... |
nginx 命令:
1 2 |
$ /usr/local/nginx/sbin/nginx -t # 检查配置文件 $ /usr/local/nginx/sbin/nginx -s reload # 重新加载 |
引申
什么是x509证书
X509 其实就是证书的一种规范,严格说与文件扩展名也没有直接关系,详细参考维基百科 x.509:
X.509 是密码学里公钥证书的格式标准。 X.509 证书己应用在包括 TLS/SSL 在内的众多 Intenet 协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509 证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构 CA 的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名.
另外除了证书本身功能,X.509 还附带了证书吊销列表和用于从最终对证书进行签名的证书签发机构直到最终可信点为止的证书合法性验证算法。
x509 证书一般会用到三种类型的文件:key、csr、crt。
key
是服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密。
csr
是证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名。
crt
是证书文件,由证书颁发机构(CA)签名或者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息,签署人用自己的 key 给你签署的凭证。
证书格式和编码方式
证书格式:
x509 ,这种证书只有公钥,不包含私钥。
pcks#7 ,这种主要是用于签名或者加密。
pcks#12 ,这种含有私钥,同时也含有公钥,但是有口令保护。
编码方式:
.pem 后缀的证书都是 base64 编码。
.der 后缀的证书都是二进制格式。
x509 是数字证书的规范。PKCS#7 和 PKCS#12 是两种封装形式。
P7 一般是把证书分成两个文件,一个公钥一个私钥,有 PEM 和 DER 两种编码方式。PEM 是纯文本的 base64 编码,P7 一般是分发公钥用,看到的就是一串可见字符串,扩展名经常是 .crt
、.cer
、.key
等。DER 是二进制编码。
P12是把证书压成一个文件,.pfx
。主要是考虑分发证书,私钥是要绝对保密的,不能随便以文本方式散播。所以 P7 格式不适合分发。.pfx
中可以加密码保护,所以相对安全些。
在实践中要中,用户证书都是放在 USB Key 中分发,服务器证书经常还是以文件方式分发。服务器证书和用户证书都是X509证书,就是里面的属性有区别。
格式转换
- crt + key 转 pfx【pfx是证书安装包,方便在电脑上直接双击按向导安装证书】
1$ openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx
- pfx 转化为 pem【curl 需要 pem 格式文件】
1$ openssl pkcs12 -in client.pfx -nodes -out client.pem
- crt + key转 p12【apache 的 cxf 客户端支持 jks 和 p12 证书】
1$ openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
- crt 转 jks【jks 支持存放信任证书,而 pkcs12 不支持,所以 tomcat 环境下配置 ca 只能使用 jks 才能保证 ca 密钥不泄露】
1$ keytool -import -v -trustcacerts -storepass defaultpwd -keypass defaultpwd -file ca.crt -keystore ca_only.jks
部分参考图片
生成了 pem 格式的根证书,自签名证书,所以无需生成证书请求文件:
生成了客户端证书,使用了默认的配置文件 openssl.cnf
:
参考
OpenSSL中文手册之命令行详解(未完待续)
手册 OpenSSL 之 req 命令
OpenSSL简介
细说 CA 和证书
CA认证
openssl x509(签署和自签署)
openssl TXT_DB error number 2 failed to update database
chrome 是不是不支持内网 ip 的 ssl 证书了?
笔记:OpenSSL 生成「自签名」证书遇到的 missing_subjectAltName 问题
openssl生成SSL证书的流程
总结之:CentOS6.5下openssl加密解密及CA自签颁发证书详解
使用nginx作为反向代理解决前后端分离时前端https,后端http造成访问无法被加载
全站 HTTPS 没你想象的那么简单
Stack Overflow 的 HTTPS 化:漫漫长路的终点
x509和pkcs12以及pkcs7的关系
FILIPPO.IO
转自:https://www.gokuweb.com/operation/d95eae05.html#san-extension
0 Comments