在互联网环境中,数据安全是每个开发者和用户都会关注的核心问题。HTTPS(HyperText Transfer Protocol Secure)是一种基于加密传输的网络协议,是应用层保护通信安全、防止数据被窃听和篡改的主要手段。
在很多一线企业,例如腾讯、阿里、字节等,许多应用强制要求使用 HTTPS 协议进行通信,Kubernetes 也提倡通过 HTTPS 协议进行通信。那么,为什么建议通过 HTTPS 协议而非 HTTP 协议?这源于二者的核心区别:
- HTTP 协议以明文方式传输数据,在网络中传输时可能遭受窃听、篡改或冒充攻击,安全性较低,存在数据泄露风险;
- HTTPS 协议基于 HTTP 协议增加了 SSL 安全层,通过加密通道传输数据,安全性更高。
通常,HTTPS 协议主要实现以下两类功能:
- 数据传输加密: 通过 HTTPS 传输的数据始终以加密形式存在,确保信息安全;
- 身份认证: HTTPS 支持单向认证和双向认证。单向认证用于验证服务端的真实性,双向认证则同时验证服务端和客户端的合法性。
在实际的企业应用中,HTTPS 的使用方式主要包括:
- 利用 HTTPS 的数据加密能力,启用单向认证验证服务端的合法性,客户端认证则采用其他方式,例如 Bearer 认证。miniblog 项目采用的正是这种方式;
- 利用 HTTPS 的数据加密能力,同时通过双向认证验证服务端和客户端的合法性。
由于 CA 认证和 HTTPS 认证流程经常在面试中被考察,同时 miniblog 在启用 HTTPS 服务时需要理解相关内容。接下来,本课程将对这两部分进行详细介绍。
什么是 HTTPS?
HTTPS 是 HTTP(超文本传输协议)的安全版本。它通过在 HTTP 和传输层之间加入 SSL/TLS(安全套接字层/传输层安全协议)来确保通信安全。相比 HTTP,HTTPS 增加了三项核心功能:
- **数据加密:**通过加密技术,确保通信内容不会被第三方窃听;
- **身份验证:**通过服务器证书验证服务器身份,防止中间人攻击;
- 校验数据是否在传输过程中被篡改。
使用 HTTPS 后,数据从客户端到服务器的整个过程都被加密保护,只有通信双方才能解码数据。
认识 CA 证书
CA 证书的内容较多,可以从以下四个方面掌握 CA 证书相关知识:
- CA 证书相关名词;
- CA 证书签发流程;
- CA 证书认证流程;
- CA 证书签发实战。
CA 证书相关名词
CA 证书涉及众多名词,以下整理了一些核心名词,供参考:
- CA: 数字证书认证机构(Certificate Authority,简称 CA),是负责发放和管理数字证书的权威机构,作为受信任的第三方,承担公钥体系中公钥合法性检验的职责;
- CA 证书: CA 证书是由 CA 签发的数字证书,其格式可能有所不同,目前最常使用的是 X.509 证书格式;
- 公钥和私钥: 公钥(Public Key)和私钥(Private Key)是一对密钥,通过特定算法生成。公钥是密钥对中公开的部分,通常用于加密会话密钥、验证数字签名或加密需通过相应私钥解密的数据;私钥则是非公开的部分;
- 加密算法: 可以使用多种加密算法对数据进行加密。常见的加密算法包括以下两类:
- 对称加密: 只有一个密钥进行加密和解密,密钥相同且加解密速度较快。典型的对称加密算法包括 DES 和 AES 等;
- 密钥以成对形式出现(公钥和私钥),公钥和私钥互为匹配,且无法通过公钥推导出私钥,反之亦然。公钥用于加密时需通过私钥解密,私钥用于加密时需通过公钥解密。与对称加密相比,其速度较慢。典型非对称加密算法包括 RSA 和 DSA 等。
- X.509 证书编码格式: X.509 证书可能采用不同的编码规则。目前编码格式主要包括以下两种:
- PEM(Privacy Enhanced Mail): 文本格式,文件后缀为 .pem,以
-----BEGIN XXXXXX-----
开头,-----END XXXXXX-----
结尾,内容为 BASE64 编码。多用于 Apache 和 UNIX 服务器; - DER(Distinguished Encoding Rules): 二进制格式,文件后缀为 .der,不可读。多用于 Java 和 Windows 服务器。
- PEM(Privacy Enhanced Mail): 文本格式,文件后缀为 .pem,以
- **X.509 证书文件后缀:**X.509 证书的文件后缀不一定是 .pem 或 .der,以下是常见类型:
- CRT(.crt): 代表 Certificate,意为证书,常见于 UNIX 系统,可能采用 PEM 或 DER 编码,大多数为 PEM 编码;
- CER(.cer): 代表 Certificate,意为证书,常见于 Windows 系统,可能采用 PEM 或 DER 编码,大多数为 DER 编码;
- KEY(.key): 通常存放公钥或私钥,虽非 X.509 证书,但其编码格式可能为 PEM 或 DER;
- CSR(.csr): Certificate Signing Request,即证书签名请求。CSR 不是证书,而是向权威证书颁发机构申请签名证书的请求,其主要包含一个公钥及附加信息。在生成申请时,会同时生成一个私钥,需自行妥善保管,无需提交给 CA 机构。
需要特别注意的是,如果证书文件的后缀是.pem 或.der,在文件名中应体现文件所属类别,例如:server-key.pem 表示私钥文件,server-crt.pem 表示证书文件。
为了更好地理解 CA 相关内容,接下来将以 CA 的签发流程为主线,在介绍流程的同时,阐述相关概念,CA 的认证流程实际上也是 HTTPS 的认证流程。
CA 证书的签发流程
CA 证书认证流程如下图所示。
上图所示的流程解释如下:
- 服务端向第三方机构 CA 提交公钥、组织信息、个人信息(如域名)等内容并申请认证(无需提交私钥);
- CA 通过线上、线下等多种手段验证申请者提供信息的真实性,例如确认组织是否存在、企业是否合法、是否拥有域名的所有权等;
- 如果信息审核通过,CA 会向申请者签发认证文件(证书):
- 证书包含以下信息:申请者的公钥、组织信息和个人信息、签发机构 CA 的信息、证书有效期、证书序列号等明文信息,同时还包含一个签名;
- 签名的生成算法:首先,使用散列函数计算明文信息的信息摘要,然后,采用 CA 的私钥对信息摘要进行加密,生成的密文即为签名。
- 客户端向服务端发出请求后,服务端返回服务端的证书文件;
- 客户端读取服务端证书中的明文信息,并使用相同的散列函数计算信息摘要。随后,利用对应 CA 的公钥解密签名数据并对比信息摘要。如果两者一致,则可以确认证书的合法性,即公钥合法。同时,客户端还需验证证书中的域名信息、有效期等内容。客户端通常内置信任 CA 的根证书(包含公钥),如果 CA 不被信任,则无法找到对应 CA 的证书,该证书将被判定为非法;
- 客户端生成一个随机数 R,并用服务端证书中的公钥加密后发送给服务端。服务端使用其私钥解密获取随机数 R,随后双方使用对称加密算法进行数据交换。
提示:
证书由以下部分组成:公钥(服务端生成的密钥对中的公钥)+申请者与颁发者信息+签名(使用 CA 机构生成的密钥对中的私钥进行签名)。颁发证书的过程实际上是 CA 使用其私钥对证书请求文件进行签名。
CA 认证流程
CA 证书的认证分为单向认证和双向认证。在实际开发中,可根据需要自行选择:
- **单向认证:**适用于无需在通信层对用户身份进行验证的场景,一般在应用逻辑层保证用户的合法登录。单向认证也是企业应用中,使用最多的认证方式;
- **双向认证:**要求通信双方相互验证身份。例如,在企业应用服务之间存在互调关系时,可能需要对通信双方进行身份验证。
(1)单向认证流程
单向认证流程如下图所示。
上图 已经清晰的展示了单向流程的步骤,这里不再详解。需要注意的是第 3 步使用的是 CA 机构证书(根证书)的公钥来解密签名。
通过上述单向认证流程可以看出,整个流程需要以下三个证书文件:根证书、服务器端公钥证书、服务器端私钥文件。
(2)双向认证流程
单向认证仅验证了服务端的身份。如果有人冒充客户端,该如何应对?此时可以采用双向认证。
双向认证 SSL 握手过程与单向认证有所不同,其大部分步骤与单向认证过程相同。但在客户端成功验证服务器后,新增了服务器验证客户端的流程步骤。双向认证流程如下图所示。
通过上述双向认证流程可以看出,整个双向认证过程需要 5 个证书文件:根证书、服务器端公钥证书、服务器端私钥文件、客户端公钥证书、客户端私钥文件。
CA 证书签发实战
CA 证书由权威的 CA 机构签发,其签发流程较为复杂且费用较高。在后端应用开发中,通常由开发或运维人员自行生成根证书及其私钥,并扮演 CA 的角色,负责为其他服务端和客户端签发证书,此类证书也称为自签证书。
在企业应用开发中,可以使用 openssl 工具来签发根证书、服务端证书和客户端证书。使用 openssl 工具签发证书具体包括以下几步:
- 签发根证书和私钥;
- 生成服务端证书;
- 生成客户端证书;
步骤一:签发根证书和私钥
签发根证书和私钥包括以下 3 步操作:生成根证书私钥、生成请求文件、生成根证书。
(1)生成根证书****私钥
使用以下命令生成根证书私钥:
$ openssl genrsa -out ca.key 1024
genrsa
子命令主要用于生成 RSA 私钥。命令行格式:openssl genrsa [args] [numbits]
。涉及参数说明如下:
-out file
:将生成的私钥保存至指定的文件中;numbits
:指定生成私钥的大小,默认是2048
。
(2)生成请求文件
使用证书私钥生成请求文件,命令如下:
$ openssl req -new -key ca.key -out ca.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=devops/OU=it/CN=127.0.0.1/emailAddress=colin404@foxmail.com"
req
子命令主要用于创建证书请求文件,其命令行格式为:openssl req [options] <infile> outfile
。参数说明如下:
-new
:创建新的证书请求文件;-key file
:指定创建证书请求所使用的私钥文件;-out arg
:指定输出文件路径;-subj arg
:设置或修改证书请求中的主体信息。
证书请求的主体信息选项说明如下:
- **CN(Common Name):**指定证书中标识身份的名称,该名称必须唯一。通常填写需要申请 SSL 证书的域名(domain)或子域名(subdomain);
- C(Country): 国家代码;
- ST(State): 州或省;
- L(Locality): 城市;
- O(Organization): 组织名称;
- OU(Organizational Unit): 组织单位名称。
提示:
不同证书的 CSR 文件,其 CN、C、ST、L、O、OU 的组合必须不同。在创建后续证书的 CSR 文件时,CN 必须各不相同,而 C、ST、L、O 和 OU 可以相同,以实现区分证书的目的。
(3)生成根证书
执行以下命令生成根证书:
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
x509 命令主要用于创建和修改 x509 证书,其命令行格式如下:openssl x509 [options] <infile> outfile
。参数说明如下:
-in arg
:指定输入文件,默认为标准输入;-out arg
:指定输出文件,默认为标准输出;-req
:指定输入文件为证书请求;-signkey arg
:指定用于自签名的私钥文件;-CA arg
:设置 CA 文件,必须为 PEM 格式;-CAkey arg
:设置 CA 私钥文件,必须为 PEM 格式;-CAcreateserial
:创建序列号文件。
步骤二:生成服务端证书
执行以下命令来生成服务端证书:
# 1. 生成服务端私钥
$ openssl genrsa -out server.key 1024
# 2. 生成服务端公钥
$ openssl rsa -in server.key -pubout -out server.pem
# 3. 生成服务端向 CA 申请签名的 CSR
$ openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=serverdevops/OU=serverit/CN=127.0.0.1/emailAddress=nosbelm@qq.com"
# 4. 生成服务端带有 CA 签名的证书
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
上述命令中,rsa
子命令主要用于处理 RSA 公私钥文件。命令行格式:openssl rsa [options] <infile> outfile
。涉及参数说明如下:
-in arg
: 指定输入文件;-pubout
:指定输出文件为公钥,默认为私钥;-out arg
:指定输出文件。
步骤三:生成客户端证书
执行以下命令来生成客户端证书:
# 1. 生成客户端私钥
$ openssl genrsa -out client.key 1024
# 2. 生成客户端公钥
$ openssl rsa -in client.key -pubout -out client.pem
# 3. 生成客户端向 CA 申请签名的 CSR
$ openssl req -new -key client.key -out client.csr -subj "/C=CN/ST=Guangdong/L=Shenzhen/O=clientdevops/OU=clientit/CN=127.0.0.1/emailAddress=nosbelm@qq.com"
# 4. 生成客户端带有 CA 签名的证书
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in client.csr -out client.crt
miniblog 实现 HTTPS 通信
如果你想学习真实项目中,如何设计和实现 HTTPS 通信,可阅读 github.com/onexstack/m… 源码。