1、前言
OSS 作为互联网基础存储产品,提供Restful API 以标准的HTTP 及 HTTPS 方式接入,用户可以选择使用OSS对外提供的标准Endpoint 访问,也可以使用自定义域名的方式访问。在使用HTTPS时,如果使用OSS 域名访问,OSS 会提供标准域名的自有证书,同时保证证书的可用性;如果使用自定义域名,则需要用户在OSS上托管自定义域名证书,当前OSS 证书托管功能已经与Aliyun 证书平台对接,OSS及证书平台会提供证书的一系列证书管理及报警功能,方便用户进行证书运维。
无论是使用OSS 官方提供的域名还是自定义域名,都会涉及到HTTPS,在使用HTTPS 的过程中也会遇到各种各样的问题,本文会对一些基础的HTTPS 概念及问题进行介绍,希望能够解决使用HTTPS 过程中遇到的大部分问题。
2、HTTPS 证书
证书是一个包含公钥、申请人及其他相关信息以及证书颁发者数字签名的文件,有 ASN.1、BER、DER 及 PEM 多种格式,不同格式的证书可以通过opensslx509 命令进行转换,通常大家看到的基本都是PEM 格式,这是DER 格式证书base64 编码后形成的,利于传播和查看;证书中包含 版本、系列号、签名算法、颁发者、有效期、生效域名等一系列信息,可以通过openssl 命令进行查看。
openssl x509 -text -in cert.crt
3、HTTPS 证书类型
3.1、按域名分
常规理解一张证书一个域名,其实并非如此,一张证书中不但可以包含单域名,还可以包含范域名,而且同时可以包含多个,理论上只要你不嫌证书大,并且足够有钱,一张证书内可以包含无数个域名。
以证书中包含的域名维度划分,一张HTTPS 证书可以包含 单域名、泛域名、多个单域名,多个单域名及泛域名。
1、单域名证书, 只覆盖一个域名
2、泛域名证书, 只覆盖一个泛域名
3、SAN 域名证书, 覆盖多个域名
4、泛SAN 域名证书, 覆盖多个单域名及泛域名
举个例子,OSS 线上部署的自有域名证书就是一张范SAN 域名证书,在一张证书中包含了多个单域名及范域名。
3.1.1 范域名证书域名生效范围
注意!!!和泛域名解析不一样,泛域名证书只对当前域名的一级子域名生效,因此在申请证书时需要注意。
举例来说,当证书中只包含 *.example.com 时,https://example.com 和 https://level2.level1.example.com 的访问都会报证书域名不匹配。
以OSS 证书为例:
访问 https://bucket.oss-cn-hangzhou.aliyuncs.com 域名校验正常。
而访问 https://bucket.bucket.oss-cn-hangzhou.aliyuncs.com 这个二级子域名,则会报HTTPS 域名不匹配错误。
3.1.2 使用范SAN 证书注意事项
使用泛SAN 证书无疑是降低证书维护的复杂度,但是也带来一些问题。
1、证书包含信息过多,导致证书Size 过大
a、证书过大会导致客户端存储证书需要更多的内存,部分嵌入式设备可能会访问失败
b、TLS 握手过程占用更多的RT ,size 最好低于一个initcwnd可发送的数据(14k左右)
2、故障爆炸半径大,证书出问题影响所有生效域名
a、因运维导致的证书过期未及时更新
b、证书私钥泄露,相当于公私钥都直接对外
c、证书因某种原因被CA 吊销,证书中任何一个域名使用违规则会导致整张证书被吊销
3.2 按类型分
为了给企业提供更高的安全性,CA 厂商提供不同类型身份级别校验的证书
1、DV 证书,域名认证,只需证明你是域名所有者即可,最常见的为TXT 验证。
2、OV 证书,组织认证,需证明申请者可代表某组织申请证书,比如AlibabaGroup。
3、EV 证书,扩展认证,需要校验该申请者的一系列其他信息是否正确,申请时间较长。
其中DV 和 EV 只支持单域名和多域名,不支持泛域名,OV 全部支持
DV 证书:
OV 证书:
EV 证书:
三者技术原理都是一样的,从技术角度安全性也一样,OV EV 只是 CA 帮助校验的信息更多,签到证书中的信息也更多,人为增强了证书的安全性。
4、PKI 信任体系
4.1、证书申请简化流程
1、证书申请人向具备一定资质的“登记机构”发起申请
2、登记机构核对完相关信息无误后将申请提交给CA 厂商。
3、CA 证书签发成功后由登记机构交给证书申请人。签发好的证书通常包含 证书、私钥和证书链。
4.2、证书验证简化流程
1、服务端根据TLS 握手中的SNI 返回相匹配的证书,如果无SNI 或者五最佳匹配,则返回默认证书。
2、客户端校验证书是否权威机构签发
3、客户端校验证书域名是否匹配
4、客户端通过CRL 及 OCSP 方式验证证书是否被吊销(通常浏览器会异步做这一步,后台程序或内网服务端程序通常会忽略此步骤)。
4.3、何为证书权威机构(CA)
能够正常签发证书的 CA 从社交工程角度需要具备一定资质,满足一系列安全及监管要求;从技术角度需要将自己的根证书广泛内置在不同的客户端及根证书库中。比如内置到Linux 及 Windows 操作系统及Chrome 及Firefox 这些自己维护根证书库的主流浏览器的根证书库中,这样才能让自己签发的证书正常被客户端访问到。
证书签发及校验流程图:
5、证书链
5.1、证书链
目前大部分证书并不是由CA 的根证书直接签发,因为根据要求根证书必须要离线保存,无法应对频繁的证书签发需求,因此会用根证书先签发出一个中间证书,证书由中间证书签发,这个中间证书就是证书链。
这里有三个要点:
1 为了保证根安全,使用中间证书进行签发,根证书离线保存。
2 中间证书本质上也是一个根证书。
3 中间证书可能也被一些客户端内置,但不如根证书内置广泛。
通过浏览器也可以看到完整证书链,客户端和服务端进行TLS 握手时,服务端会连同证书及证书链一起返回,从证书追溯到中间证书再由中间证书追溯到最终的根证书,完成证书权威性校验。
5.2、检查证书链是否完整(以PEM 格式为例)
以PEM 格式证书为例,证书链通常紧跟着证书存放,大家可以打开PEM 格式的证书查看,如果只有一个 CERTIFICATE 块,则证明没有证书链,除非你的证书是由根证书直接签发,否则以此证书文件部署到阿里云上则会出现证书链缺失导致部分环境HTTPS 访问失败情况。
5.3 浏览器证书链自动补齐
目前互联网上有大量证书的证书链是缺失的,但是并没有被发现,原因是大部分网站是通过浏览器访问,大部分浏览器会默认将权威机构的中间证书补齐或作为根证书库的一部分,因此即使证书链缺失也可以正常访问。这也是为什么很多HTTPS 链接直接使用浏览器可以访问,但是放到程序中或者直接curl/wget 会报“证书非权威机构颁发”的错误,原因就在此。
因此在OSS 或者阿里云上部署证书时,务必确认证书链是否完整,否则部分环境访问HTTPS 会失败。
6、OSS CNAME 自定义证书
在开始之前先介绍下SNI,SNI (Server Name Indication) 是 SSL/TLS 协议的一个扩展,与HTTP Host 头部类似,如果握手时不携带SNI,则无法判断该HTTPS 请求的具体身份,只能返回默认证书,因此一个服务端只能支持一张证书,在支持SNI 扩展之后,服务端可以支持多证书。
在任何支持自定义证书的产品中,都是需要客户端携带SNI 自定义证书才能生效,否则在HTTPS 握手阶段,服务端无法判断客户端身份,只能返回默认证书。
当前大部分客户端设备HTTPS 请求都会携带SNI,但仍然有相当一部分HTTPS 请求不携带SNI,比如Nginx 的HTTPS Proxy,在默认配置下就不携带SNI。
这是TLS 握手报文中Client Hello 中的SNI 信息截图:
在进行TLS 握手时OSS 返回证书逻辑:
1、如果请求是否携带SNI,如是则继续,否则返回自有默认证书。
2、判断SNI 是否为自定义域名,如是则继续,否则返回自有默认证书。
3、判断有无托管的证书,如有则返回用户自定义证书,否则返回自有默认证书。
整体逻辑很简单,如果是自定义域名访问的HTTPS请求并且托管了证书,则返回用户自定义证书进行握手,否则返回默认证书进行握手。
因此在使用自定义CNAME 的HTTPS 访问时,务必保证客户端支持SNI,好让服务端返回正确的证书。好在当前几乎所有浏览器及openssl 客户端都支持SNI,除非使用非常古老客户端(IE6)或者主动删除SNI,否则基本都默认携带SNI。
7、常见问题&及解决办法
7.1、证书域名不匹配
a、不匹配证书任意一个域名或泛域名
b、TLS 握手未携带SNI,服务端未返回预期证书
7.2、证书非权威机构颁发
a、自签证书,或其他非权威机构签发证书
b、证书链不完整,导致无法追溯到最终根证书
c、本机根证书存在问题,根证书配置不当或根证书过期等
7.3、TLS 握手失败(原因较多)
a、协议版本不匹配,服务端或客户端不支持某个协议版本
b、服务端证书配置不正确
c、客户端服务端支持加密套件无交集
d、连接被RST,防火墙会根据sniRST 特定连接
e、证书过期
等
7.4、为什么客户端和服务端什么都对,还是建联不成功?
考虑劫持可能,HTTPS 不保证一定能成功的与服务端安全通信,但可以保证如果不安全或者和非服务端
三方不安全通信一定会被警告或阻断。所以当这种情况出现时,不要抱怨是HTTPS 让你通信不成功,这本来就是使用HTTPS 的意义所在,阻断不安全的通信。
最后附证书及HTTPS 相关实用命令
1、判断证书及私钥是否匹配
分别对证书及私钥进行如下操作,两条命令结果相同
openssl x509 -noout -modulus -in cert.crt | openssl md5
openssl rsa -noout -modulus -in priv.crt | openssl md5
2、建立一条握手后的HTTPS 连接
openssl s_client -servername $sni -connect $host:443
3、查看服务器端证书
openssl s_client -connect oss.aliyuncs.com:443
-servername www.baidu.com # 添加指定sni
-alpn h2 # alpn 沟通
4、查看服务端证书/本地证书过期时间
echo | openssl s_client -servername $sni -connect $host:443 2>/dev/null | openssl x509 -noout -dates
openssl x509 -noout -dates -text -in cert.crt
5、查看证书各类信息
openssl x509 -text -in cert.crt
6、默认根证书列表及信息
本地默认根证书列表:/etc/pki/tls/certs/ca-bundle.crt
查看所有根证书列表信息
awk -v cmd='openssl x509 -text' '/BEGIN/{close(cmd)};{print | cmd}' < /etc/pki/tls/certs/ca-bundle.crt