引言

最近在研究 gRPC 的 TLS 通信,
是时候整理一下这几个相似概念了。

  • TLS Transport Layer Security 传输层安全协议
  • SSL Secure Sockets Layer 安全套接层
  • HTTPS HyperText Transfer Protocol Secure 超文本传输安全协议
  • SSH Secure SHell 安全外壳协议

TLS/SSL

网景公司(Netscape)在1994年推出首版网页浏览器-网景导航者时,推出HTTPS协议,以SSL进行加密,这是SSL的起源。

TLS 的前身是 SSL,因此在很多场合,两者是混用的(或者是直接称之为 TLS/SSL )

公钥/私钥

背景知识:对称加密和非对称加密。

简单来说有三点:

  1. 对称加密只有一个密钥:也就是说通过密钥加密,也通过密钥解密
  2. 非对称加密有公钥和私钥:通过公钥加密的信息只能通过私钥解密;并且无法通过公钥得到私钥。
  3. 对称加密的效率要高于非对称加密

服务器端掌握公钥和私钥,
客户端掌握公钥(或者说是服务器向客户端发送公钥)

以下将描述两个场景:

场景1 通过 HTTPS 协议访问网站

  1. 客户端请求服务器
  2. 服务器返回公钥证书
  3. 客户端验证公钥证书是否合法
  4. 产生随机对称密钥,通过公钥加密后发送给服务器
  5. 服务器同私钥解密后,使用对称密钥进行对称加密通信

场景2 客户端访问访问服务器

  1. 客户端内携带公钥证书
  2. 客户端产生随机密钥,通过公钥发送给服务器
  3. 服务器通过私钥进行解密
  4. 使用密钥进行对称加密的通信

我想读者此时有几个问题:
Q1: 为什么不能使用对称加密呢?

A: 客户端和服务端必须同时拥有密钥才能进行通信,那么在这个过程中理论上密码就会有泄漏的风险:想象一下,密钥一定是从服务端或者客户端生成的,需要将密钥传给另一端的过程中必然经过危险的网络环境。因此单纯的对称加密是不可行的。

Q2: 为什么不能全部使用非对称加密呢?

A:因为非对称加密的效率不如对称加密。通过安全的方式将对称加密密钥送到另一端,那么对称加密也是安全的。

HTTPS

HTTPS 也就是使用TLS 的HTTP,也就是上一小节中提到的场景1的情况。

HTTP3

HTTP/3是第三个主要版本的HTTP协议。与其前任HTTP/1.1和HTTP/2不同,在HTTP/3中,将弃用TCP协议,改为使用基于 UDP 协议的 QUIC 协议实现。

HTTP3虽然弃用了TCP,但仍然使用TLS,实际上是使用QUIC协议耦合了从UDP到TLS到HTTP

SSH

SSH(Secure Shell)是一种网络协议,用于在不安全的网络上安全地进行远程登录和文件传输。它提供了加密的通信通道,以保护数据在客户端和服务器之间的传输安全。

SSH 和 TLS 是很相似的,两者采用的加密思路也是相似的。
但是其作用的范围和场景是不同的。

PGP 和 GPG

PGP(英语:Pretty Good Privacy,直译:优良保密协议)是一套用于讯息加密、验证的应用程序。
开源并具有同类功能的工具名为GnuPG(GPG)。PGP及其同类产品均遵守 OpenPGP 数据加解密标准(RFC 4880)

PGP加密由一系列散列、数据压缩、对称密钥加密,以及公钥加密的算法组合而成。每个步骤均支持几种算法,用户可以选择一个使用。每个公钥均绑定一个用户名和/或者E-mail地址。

应用实例

使用 PGP 密钥签名和加密邮件

签名旨在证明这封邮件确实是本人发出,
而加密旨在使邮件内容不能被中间人监听。

Thunderbird 等邮件客户端已经将此功能集成,此节使用命令生成一个PGP密钥

需要注意的是必须与收件人进行过一次通信(并且携带了公钥)才能进行加密通信。

1
gpg --gen-key

输入你的姓名和邮箱、输入密码就可以生成一个默认的gpg密钥

使用 GPG 密钥认证加密 git commit 到 GitHub

查看本机所有密钥

1
gpg --list-secret-keys --keyid-format=long

复制其中想用的一条的长形式密钥,并且

1
gpg --armor --export [long secret key]

复制粘贴到github即可。
需要注意的是电子邮箱需要是经过github认证后的邮箱。

使用 OpenSSL 生成CA证书

CA证书需要证书签发机构进行签名,
但如果只是需要使用 TLS 进行 C-S 架构的通信,生成一个自签名的CA证书也未尝不可。

生成一个RSA密钥

1
openssl genrsa -out server.key 2048

生成对应的公钥

1
openssl rsa -in server.key -pubout -out server.pub.key

生成签名请求文件

1
openssl req -key server.key -out server.csr

生成CA自签名证书

1
openssl req -keyout ca.key -nodes -out ca.crt -x509 -days 365

自签名(这个操作覆盖了原来的server.crt)

1
openssl x509 -req -days 365 -in server.csr -signkey ca.key -out server.crt

这时,
server.crt文件就是服务器的公钥(自签名)
server.key是私钥(绝不能暴露)

附赠一个 nginx 的配置文件:

1
2
3
4
5
6
7
8
9
server {
	listen 443 ssl;
	server_name example.com;
	ssl_certificate /pathtocert/server.crt;
	ssl_certificate_key /pathtocert/server.key;
	location / {
		# something...
	}
}