HTTPS和证书链
目录:
记一次HTTPS证书问题导致线上内网HTTPS调用失败
起因
ads在调用https://api-share.daweixinke.com的https接口的时候产生以下报错
https:\/\/api-share.daweixinke.com\/inner\/share\/mkey?os=ADS","data":{"cck_uid":"684762","sg":"ec05a2ea43b71bad2a3e38170123b6c0"}} ### res: ### cost: 0.042207002639771 s, ### error: curl error: SSL certificate problem: certificate has expired
反馈的信息就是,证书不可用
现象
- 内网调用https服务报证书过期的错误,而浏览器,手机浏览器,微信内打开都是正常的
- CentOS6系统调用有问题,CentOS7系统调用没有问题
排查
使用openssl命令
$ openssl s_client -connect ark-api.daweixinke.com:443 -showcerts
可以在开头看到
verify error:num=10:certificate has expired
notAfter=Aug 21 04:00:00 2018 GMT
verify return:0
结尾也有
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES128-GCM-SHA256
Session-ID: 2496BA2F46C8EED68D6DDFE57D9BE0D616D601E47B590D8AE8A0A18D13D9E270
Session-ID-ctx:
Master-Key: D840CF6423438571F5E21A772228C067E0917D3690BF2E02DDE123C56BFDF9A9D2F56ACA0012B9991AC12EF180EF7C19
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
TLS session ticket lifetime hint: 100800 (seconds)
TLS session ticket:
0000 - 50 bb 2f ff fb 6b a4 e1-7c db 6d 4c 62 39 f8 de P./..k..|.mLb9..
0010 - fb 11 59 6c 35 47 55 11-48 c1 4c 64 96 39 37 38 ..Yl5GU.H.Ld.978
0020 - 8d e2 b6 3e 93 ef 9a e1-99 93 45 a7 f4 ed c0 0c ...>......E.....
0030 - c7 74 34 bb c9 99 3a a4-62 ec e2 40 86 a1 bc fd .t4...:.b..@....
0040 - 3c e7 c7 02 cb b1 5b c9-21 0b fd df 34 3a 34 46 <.....[.!...4:4F
0050 - e7 4e fe 7e 7d cf 8a 72-c5 cb 7d dd 4f 17 09 08 .N.~}..r..}.O...
0060 - 38 99 11 b7 82 df 3b 8a-77 e4 b8 51 01 9c f6 65 8.....;.w..Q...e
0070 - b6 95 75 6d 67 28 9b 7c-b3 d5 4b 42 12 34 2f 2e ..umg(.|..KB.4/.
0080 - 64 82 bc 0c 3b be d8 91-31 f4 46 fb f1 a1 7f 1c d...;...1.F.....
0090 - e8 fb c7 69 60 87 4f 09-19 8b 18 6b 97 c2 45 24 ...i`.O....k..E$
00a0 - e4 1d 1c ab e3 4b 8d d0-10 2f d1 28 9b 8a 76 73 .....K.../.(..vs
Start Time: 1534833217
Timeout : 300 (sec)
Verify return code: 10 (certificate has expired)
在北京时间2018年8月21日12时的时候过期
使用curl命令
$curl -v https://ark-api.daweixinke.com
* About to connect() to ark-api.daweixinke.com port 443 (#0)
* Trying 140.143.49.222... connected
* Connected to ark-api.daweixinke.com (140.143.49.222) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.daweixinke.com,OU=运维部,O=北京醋溜网络科技股份有限公司,L=北京,ST=北京,C=CN
* start date: Jan 19 00:00:00 2017 GMT
* expire date: Jan 19 23:59:59 2019 GMT
* common name: *.daweixinke.com
* issuer: CN=GeoTrust SSL CA - G3,O=GeoTrust Inc.,C=US
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: ark-api.daweixinke.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 21 Aug 2018 06:57:52 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 0
< Connection: keep-alive
< Server: openresty/1.11.2.3
< Last-Modified: Mon, 20 Aug 2018 08:42:03 GMT
< ETag: "5b7a7edb-0"
< Accept-Ranges: bytes
<
* Connection #0 to host ark-api.daweixinke.com left intact
* Closing connection #0
可以看到curl能正常请求
原因
最后发现是证书链上第三个证书过期了
获取方式复制-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
之间的内容,然后直接存入以.crt结尾的文档中,windows系统中能正常识别,可以看到是上级证书失效了。
非对称加密以及电子证书相关的基础概念
- a有公钥和私钥
- a把公钥分发给b,c,d
- b如果想给a发送信息,可以通过a的公钥进行加密然后传输给a
- a可以通过自己的私钥进行解密看到信息,如果私钥不泄露,那别人拿到信息也不能读取到内容
- a回复信息会将自己的信息通过Hash函数处理得到digest(摘要)
- 通过私钥将digest(摘要)进行加密获得signature(数字证书)
- 然后将signature(数字证书)放到信息后一起回复给b
- b拿到信息,将signature(数字证书)通过公钥生成digest(摘要)
- 将信息通过Hash函数处理得到digest(摘要),将两个digest(摘要)对比确认消息是否被修改
- 如果c把自己的公钥假冒a的公钥给到b,b在不知情的情况下,c就可以通过自己的私钥生成signature(数字证书)发送消息给b,b可以用假的公钥解密进而传递消息
- 为了解决这情况,b无法确定a的公钥是否属于a,a可以去CA(certificate authority,简称CA,证书中心)做公钥认证,CA(证书中心)用自己的私钥,对a的公钥和相关信息进行加密,生成Digital Certificate(CA数字证书)
- 有了数字证书,a回给b的时候可以在signature(数字证书)后加上Digital Certificate
- b收到信息把Digital Certificate用CA的公钥进行解密得到a的公钥,然后重复8和9步骤确定信息是否被修改
- https协议用于网页加密
- client像server进行加密请求
- server用自己的私钥进行加密网页返回给网页,连通数字证书一同发给client
- client的证书管理器有“受信任的根证书颁发机构列表”,然后查看数字证书的公钥是否在列表中
- 如果数字证书记载的网址,和你正在浏览的网址不一致就会提示证书可能被冒用的警告
- 如果数字证书不是收信任机构颁发,会提示时候添加此信任机构
- 如果数字证书是可靠的,client就可以通过该公钥进行加密消息,与server进行加密信息交换
参考阮老师的博客
https协议
https建立在tcp连接上,使用TSL协议
过程
流程为
对于初次建立
在建立完成TCP连接后,开始TLS握手过程
- Client发起握手请求,向Server发送一个ClientHello消息,内容包括其所支持的SSL/TSL,Cipher Suite加密算法列表,sessionID,随机数
- Server在收到Client请求后,会去session缓存中查找是否有相同值,如果没有相同值,会给Client发送ServerHello消息,内容包括SSL/TSL,Cipher Suite加密算法列表中的加密算法,sessionID,随机数
- Server向Client发送Certificate,包含公钥、签名、证书机构等信息。
- Server向Client发送ServerKeyExchange消息,包含Server的EC Diffie-Hellman算法相关参数,一般在DHE和DH_anon等加密算法组合时才会由Server端发出
- Server向Client发送ServerHelloDone消息,表示Server端握手消息发送完成
- Client收到Server的证书,回去验证证书,认为证书可信之后,向Server发送ClientKeyExchange消息,包括Client端
EC Diffie-Hellman
算法相关参数,Server和Client需要根据接收到对方的参数和自身参数算出Premaster secret,为生成秘钥做准备
- Client向Server发送ChangeCipherSpec消息,告知Server端开始使用加密方式发送消息
- Client通过握手过程获取的Server端随机数,客户端随机数,
Premaster secret
计算生成会话密钥Master Secret
(加密传输所使用的对称加密秘钥),以Master Secret
密钥加密方式向Server发送Finished消息,内容就是之前收发所有的握手消息的Hash值和MAC值,用于验证加密服务是否可用
- Server接收到消息进行解密,校验其中Hash值和MAC值,以
Master Secret
密钥加密方式发送ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据
- Server以
Master Secret
密钥加密方式向Server发送Finished消息,消息内容为所有收发握手消息的Hash和MAC值,用于Client校验
如果Client端和Server都校验成功,则TLS握手阶段完成,双方按照记录协议的范围使用协商生成的会话秘钥加密发送数据。
Server端Session ID缓存
- Client发起握手请求,向Server发送一个ClientHello消息,内容包括其所支持的SSL/TSL,Cipher Suite加密算法列表,sessionID(长度为0),随机数
- Server在收到Client请求后,会去session缓存中查找是否有相同值,如果有相同值,会给Client发送ServerHello消息,内容包括SSL/TSL,Cipher Suite加密算法列表中的加密算法,sessionID,随机数,然后通过sessionIO建立快速握手
- Server向Client发送ChangeCipherSpec消息,告知Client端开始使用加密方式发送消息
- Server通过握手过程获取的服务端端随机数,客户端随机数,
Premaster secret
计算生成会话密钥Master Secret
(加密传输所使用的对称加密秘钥),以Master Secret
密钥加密方式向Server发送Finished消息,内容就是之前收发所有的握手消息的Hash值和MAC值,用于验证加密服务是否可用 - Server接收到消息进行解密,校验其中Hash值和MAC值,以
Master Secret
密钥加密方式发送ChangeCipherSpec消息,通知客户端此消息以后服务器会以加密方式发送数据 - Server以
Master Secret
密钥加密方式向Server发送Finished消息,消息内容为所有收发握手消息的Hash和MAC值,用于Client校验
client和server通过缓存Session ID可以快速建立TLS握手,但是这么做也有一些弊端
- 负载均衡中,多机之间往往没有同步Session信息,如果客户端两次请求没有落在同一台机器上就无法找到匹配的信息
- 服务端存储
Session ID
对应的信息不好控制失效时间,太短起不到作用,太长又占用服务端大量资源。而Session Ticket
(会话记录单)可以解决这些问题,Session Ticket
是用只有服务端知道的安全密钥加密过的会话信息,最终保存在浏览器端。浏览器如果在ClientHello
时带上了Session Ticket
,只要服务器能成功解密就可以完成快速握手。
证书链
证书 & CA
证书
维基百科介绍对证书的介绍是In cryptography, a public key certificate (also known as a digital certificate or identity certificate) is an electronic document used to prove ownership of a public key.
,翻译一下就是证书是用来认证公钥持有者的身份的电子文档,防止第三方进行冒充。一个证书中包含了公钥、持有者信息、证明证书内容有效的签名以及证书有效期,还有一些其他额外信息
CA
CA就是签发电子证书的实体
Signing & Verification
证书的签发(Signing)和认证(Verification)的过程
签发证书的步骤:
- 首先撰写证书的元信息: 签发人(Issuer)、地址、签发时间、过期失效等;当然,这些信息中还包含证书持有者(owner)的基本信息,例如owner的DN(DNS Name,即证书生效的域名),owner的公钥等基本信息
- 通过通用的Hash算法将信息摘要提取出来
- Hash摘要通过Issuer(CA)私钥进行非对称加密,生成一个签名密文
- 将签名密文attach到文件证书上,使之变成一个签名过的证书
验证证书的步骤:
- 浏览器获得之前签发的证书
- 将其解压后分别获得“元数据”和“签名密文”
- 将同样的Hash算法应用到“元数据”获取摘要
- 将密文通过Issuer(CA)的公钥(非对称算法,私钥加密,公钥解密)解密获得同样的摘要值
- 比对两个摘要,如果匹配,则说明这个证书是被CA验证过合法证书,里面的公钥等信息是可信的
证书链
证书链
证书链是用于保证在验证过程中,解密摘要等所使用的签发者的公钥有效。
证书分三类
- end-user:包含用来加密传输数据的公钥的证书,是HTTPS中使用的证书
- intermediates:CA用来认证公钥持有者身份的证书,即确认HTTPS使用的end-user证书是是否隶属于某域名。这类intermediates证书甚至可以有很多级。
- root:用来认证intermediates证书是合法证书的证书。
end-user certificates & intermediates certificates
- Client端操作系统或浏览器中内置了根证书,但是Client端接收到
end-user certificates
证书后发现不是根证书签发的,无法根据本地根证书去验证end-user certificates
是否可信 - Client根据
end-user certificates
的Issuer去找该证书的颁发机构,去CA请求颁发机构的证书,判断其是否是根证书颁发的,如果本地有根证书,就可以利用根证书的公钥去验证是否通过 - 颁发机构的证书被信息后就可以利用颁发机构的证书中的公钥去验证
end-user certificates
证书的可信性
root certificates
Root CA不会直接颁发证书,而是通过中间层来进行颁发end-user证书,目的是为了确保root certificates的绝对安全性,将根证书隔离的越严格越好,确保其秘钥
其他
了解了这个证书体系之后,才明白为什么百度/google
这种公司也需要向第三方购买签名证书了,自签root证书推广起来非常困难,这也导致目前的证书市场基本上被Symantec(VeriSign/GeoTrust)
/Comodo
/GoDaddy
垄断。百度使用的是Versign
,google
使用的是GeoTrust
。目前HTTPS的推广已经不可避免,也已经有一些公益组织开始提供免费、自动化、开放的证书签发服务,例如:Let's Encrypt
问题解析
我们添加的时候,证书链上为三级,证书链第三级证书过期了。
正常配置server端证书的时候,我们需要只是第一级证书即可,其他二级和三级Client会自动去CA处查询,如果server端配置了就按照server端的算了。
但是由于微信等强制验证两级,这边我们就都配置了。
而对于CentOS7的问题,应该是对不同版本对server端证书链校验级别的问题了。