阅读视图

发现新文章,点击刷新页面。
🔲 ☆

HTTP与HTTPS区别随笔

超文本传输安全协议(HTTPS)

超文本传输安全协议(HyperText Transfer Protocol Secure),缩写HTTPS,也常称为:HTTP over TLS、HTTP over SSL 或 HTTP Secure。是一种计算机网络进行安全通信的传输协议。HTTPS经由HTTP协议进行通信,但是利用SSL/TLS来加密之间传输的数据包。HTTPS开发的主要目的是提供对网络服务器的身份认证,保护交换数据的隐私与完整性。这个协议由**网景公司(Netscape)**在1994年首次提出。

在2010年末后HTTPS开始广泛使用,以保证网页浏览的私密性。

还有一种安全超文本传输协议(S-HTTP)的HTTP安全策划三农户实现,但是HTTPS的广泛应用实现了HTTP的安全传输,S-HTTP并没有得到广泛的支持。

HTTP 和 HTTPS 的主要差异

HTTP的URL是由http://起始与默认使用端口80,而HTTPS的URL则是由https://起始与默认使用端口443

HTTP 和 HTTPS 协议层

HTTP协议和安全协议同属于应用层(OSI模型的最高层),具体来讲,安全协议工作在HTTP之下,传输层之上:安全协议向运行HTTP的进程提供一个类似于TCP的套接字,供进程向其中注入报文,安全协议将报文加密并注入运输层套接字;或是从运输层获取加密报文,解密后交给对应的进程。严格地讲,HTTPS并不是一个单独的协议,而是对工作在一加密连接(TLS或SSL)上的常规HTTP协议的称呼。

HTTPS报文中的任何东西都被加密,包括所有报头和荷载。入股被攻击者攻击,大多数情况下那个攻击者所能知道的只有在两者之间有一连接这一事实。

提供服务

要使一网络服务器准备好接受HTTPS连接,管理员必须创建一数字证书,并交由证书颁发机构签名以使浏览器接受。证书颁发机构会验证数字证书持有人和其声明的为同一人。浏览器通常都预装了证书颁发机构的证书,所以他们可以验证该签名。

获得证书

由证书颁发机构签发的证书有免费的,也有收费数美元到数千美元的。一个组织或团体也有可能有自己的证书,尤其是当浏览器来访问他们自己的网站时,如学校、公司等会使用自己的证书。

总结HTTPS和HTTP的区别

https协议需要到CA申请证书,需要交费。

http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。

http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。

http的连接很简单,是无状态的。

我是一名Linux初学者,如果你与我一样喜欢折腾,喜欢Linux,那么请加入我的电报群https://t.me/yeefire_blog,在这里畅所欲言,共同学习进步。

🔲 ☆

Nginx正向代理

1753263871737351.png

Nginx可以通过配置stream模块来实现对HTTPS的TCP四层正向代理。核心是使用proxy_pass指令将流量转发到目标服务器,同时配合ssl_preread指令处理TLS握手,实现HTTPS的透明代理。

一个简单的配置示例:

stream {
    resolver 223.5.5.5 114.114.114.114; # 配置DNS解析器
    resolver_timeout 10s;

    server {
        listen 443; # 监听的端口
        ssl_preread on; # 启用ssl_preread模块,用于处理TLS握手

        proxy_connect_timeout 10s;
        proxy_timeout 30s;
        proxy_pass $ssl_preread_server_name:$server_port; # 转发到目标服务器
        proxy_protocol on; #启用PROXY protocol
        # 可以根据需要添加其他proxy_*指令
    }
}
配置说明:
  • stream模块: Nginx的stream模块用于处理TCP和UDP的四层代理,与HTTP模块同级。

  • resolver配置DNS解析器,用于解析目标服务器的域名。

  • listen指定Nginx监听的端口,这里是20017。

  • ssl_preread on启用ssl_preread模块,这个模块允许Nginx在TLS握手阶段读取SNI (Server Name Indication) 扩展,从而获取目标服务器的域名,这对于HTTPS的透明代理至关重要。

  • proxy_pass将流量转发到目标服务器。$ssl_preread_server_namessl_preread模块提取到的SNI信息,表示目标服务器的域名,$server_port是客户端请求的目标端口。

  • proxy_connect_timeoutproxy_timeout设置连接超时和读写超时时间。

  • proxy_protocol on启用PROXY protocol,如果后端服务器支持,可以传递客户端的真实IP和端口信息。

注意事项:
  • 需要确保Nginx编译时已启用ngx_stream_ssl_preread_modulengx_stream_proxy_module模块。

  • 目标服务器需要正确配置SSL证书,以便Nginx能够正常进行TLS握手。

  • 根据实际需求,可以配置其他proxy_*指令,例如proxy_buffer_sizeproxy_next_upstream等。

  • 如果后端服务器是HTTPS的,则需要在proxy_pass中指定HTTPS协议,例如 proxy_pass https://$ssl_preread_server_name:$server_port;

配置HTTPS正向代理的流程:
  1. 客户端发起HTTPS请求,连接到Nginx的监听端口。

  2. Nginx的stream模块接收到连接,并使用ssl_preread模块读取SNI信息,获取目标服务器的域名。

  3. Nginx根据SNI信息,将请求转发到目标服务器。

  4. Nginx与目标服务器建立TLS连接,进行HTTPS握手。

  5. Nginx将目标服务器的响应返回给客户端。

通过stream模块和ssl_preread模块,Nginx可以实现对HTTPS的TCP四层正向代理,将客户端的请求透明地转发到目标服务器,并处理TLS握手。这种方式可以用于实现负载均衡、流量转发等功能,同时保持HTTPS的安全性。

相关参考:


🔲 ☆

web图像格式对比(四)

nodejs 图像处理库

说完了有损压缩和无损压缩的图像格式,来整理下 nodejs 方面图像处理相关的库。

sharp

基于 libvips 实现,提供 JPEG、PNG、GIF、Webp、AVIF 以及 SVG 图像格式的处理,包括图像格式转换,图像尺寸缩放,图像组合,图像旋转,等等多种操作,也支持将图像转换成 base64 字符串。

例如将 png 转换成 avif

 import sharp from 'sharp';

sharp('./images/rgb.png')
.toFormat('avif', { quality: 50 })
.toFile('build/images/rgb.avif')
.then(info => console.log(info));

例如将 jpeg 转成 base64

const resizedImageBuf = await require('sharp')(pathToMyImage)
.toBuffer();

console.log(`data:image/png;base64,${resizedImageBuf.toString('base64')}`);

imagemin(停止维护)

imagemin 是插件式的压缩图像的工具,可通过引入自定义的插件来支持不同图像格式的转换和图像尺寸的优化,文档相对简陋,并且本身已停止维护,常用的插件有以下这些:

import imagemin from 'imagemin';
import imageminWebp from 'imagemin-webp';

await imagemin(['images/*.{jpg,png}'], {
destination: 'build/images',
plugins: [
imageminWebp({ quality: 100 })
]
});

libsquoosh

Google 开发的 libSquoosh,支持使用 nodejs cli 转换图像格式的工具,支持 JPEG XL,具体的可以看这篇介绍 —— Introducing libSquoosh

其他构建工具

Webpack

版本loaderplugin
<= 4url-loader:支持读取图像并转换成 base64file-loader:支持读取图像imagemin-webpack-plugin(停止维护)
image-minimizer-webpack-plugin:支持使用 imageminlibsquoosh 优化图像尺寸
5内置支持 - assets module

Vite

vite-plugin-imagemin:使用 imagemin 压缩图像

Rollup

@rollup/plugin-image:支持import jpeg,png 等图像文件的语法并打包

🔲 ⭐

如何自签名带 SAN 字段的 SSL/TLS 证书

前言

在本站之前一篇文章 如何成为 CA,并签发自己的证书 中,我们介绍了如何做一个“正规”的自签名证书。

但是,这个方法对于现代的浏览器不太管用了,因为 Chrome、Firefox 等浏览器已经不再判定证书的 CN (Common Name) 字段与域名是否一致了,而是改用判定 SAN (Subject Alternative Name) 字段。具体为什么这么做以及 SAN 的含义,网上有很多解释,很重要但是这里不谈,只谈如何在自签名证书中正确配置 SAN 字段。

网上的教程有很多,但很多没有说清楚,或者缺少一些关键步骤和参数,导致实际情况下出各种问题,这里我尽量整理了一个完善的版本。

准备步骤

首先,CA 的证书与文首提到的文章一致,如果之前配置过,那就不需要再生成了。

然后,生成待签发证书的私钥,这一步也与上述文章相同:

1
openssl genrsa -out example.key 4096

关键在于 CSR 的创建

之前创建 CSR 的时候会手动输各个字段,但其中不包含 SAN 字段,所以我们需要一个配置文件来配置 SAN 字段(当然直接包含在命令行里面也行,但很麻烦)。

建议新建一个目录叫 certreq,然后在里面新建一个文件叫 req.conf,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no

[req_distinguished_name]
C = <修改为实际值>
ST = <修改为实际值>
L = <修改为实际值>
O = <修改为实际值>
OU = <修改为实际值>
CN = <修改为实际值>

[req_ext]
subjectAltName = @alt_names

[alt_names]
# 这里就是 SAN 字段,以下修改为实际值
DNS.1 = vvzero.com
DNS.2 = *.vvzero.com
IP.1 = 1.1.1.1
IP.2 = 1.1.1.2
IP.3 = 1.1.1.3

然后生成 CSR 文件:

1
openssl req -new -key example.key -out example.csr -config req.conf

检查 CSR 文件中是否存在 SAN 字段

1
openssl req -noout -text -in example.csr | grep -A 1 "Subject Alternative Name"

如果打印出了你的配置,则代表创建成功。如果没有输出,请检查有没有操作错误。

用 CA 的私钥签发证书

1
openssl x509 -req -days 365 -in example.csr -CA /path/to/CAPrivate.pem -CAkey /path/to/CAPrivate.key -CAcreateserial -out example.crt -extensions req_ext -extfile req.conf

注意其中的 -extensions req_ext -extfile req.conf 是关键,很多教程没有加这个参数,导致生成的证书丢了 SAN 字段。

验证证书的 SAN 字段

1
openssl x509 -text -noout -in example.crt | grep -A 1 "Subject Alternative Name"

同上,需要打印出正确的 SAN 配置,才算成功。

🔲 ☆

网络安全科普:详解 HTTPS 与 TLS

引言

现在的网站都推荐使用 HTTPS 来确保用户数据的安全,验证网站的所有权,防止攻击者创建虚假网站版本,以及将信任传达给用户。如果网站要求用户登录、输入个人详细信息(例如其信用卡号)或查看机密信息(例如,健康福利或财务信息),则必须对数据保密。

作为普通用户,当我们上网冲浪时,是否想过为什么越来越多的域名输入时是 HTTPS 开头而非 HTTP 么?HTTPS 相比 HTTP 多出来的 S 到底多了些什么?TLS 和 SSL 又是什么,握手机制是如何进行的?其在七层协议中处于什么位置,与 HTTPS 相关的概念比如 CA 证书、Keyless、DTLS、mTLS 又分别是些啥?当我们使用 wireshark 时又该怎么抓包分析……种种疑问,希望能通过这篇文章的介绍为大家解答其中的部分解惑。

背景与介绍

什么是 HTTPS

超文本传输协议 (Hypertext Transfer Protocol, HTTP) 是设计用于在 Web 上传输内容的协议。 HTTP 是一种简单协议,它利用可靠的传输控制协议 (Transmission Control Protocol, TCP) 服务来执行其内容传输功能。由于数据在传输过程中是明文传输,因此无法保证网络通信在传输过程中不被篡改,安全性受到限制。

超文本传输安全协议 (HTTPS) 是 HTTP 的安全版本,但 HTTPS 并不是独立于 HTTP 的协议。它只是在 HTTP 协议的基础上使用 TLS/SSL 加密。HTTPS 经过加密,以提高数据传输的安全性。

为什么 HTTPS 可以保证安全

HTTPS 使用加密协议对通信进行加密。该协议称为传输层安全性 (TLS),但以前称为安全套接字层 (SSL)。该协议通过使用所谓的非对称公钥基础架构来保护通信。这种类型的安全系统使用两个不同的密钥来加密两方之间的通信:

  1. 私钥 - 此密钥由网站所有者控制,并且如读者所推测的那样,它是私有的。此密钥位于 Web 服务器上,用于解密通过公钥加密的信息。
  2. 公钥 - 所有想要以安全方式与服务器交互的人都可以使用此密钥。用公钥加密的信息只能用私钥解密。

HTTPS安全是由一套安全机制来保证的,主要包含这4个特性:机密性、完整性、真实性和不可否认性

  • 机密性是指传输的数据是采用 Session Key(会话密钥)加密的,在网络上是看不到明文的。
  • 完整性是指为了避免网络中传输的数据被非法篡改,使用 MAC 算法来保证消息的完整性。
  • 真实性是指通信的对方是可信的,利用了 PKI(Public Key Infrastructure 即「公钥基础设施」)来保证公钥的真实性。
  • 不可否认性是这个消息就是你给我发的,无法伪装和否认,是因为使用了签名的技术来保证的。

什么是 SSL/TLS

SSL(Secure Socket Layer)是指安全套接字层,简而言之,它是一项标准技术,可确保互联网连接安全,保护两个系统之间发送的任何敏感数据,防止网络犯罪分子读取和修改任何传输信息,包括个人资料。TLS(Transport Layer Security,传输层安全)是更为安全的升级版 SSL。

TLS 1.0 版实际上最初作为 SSL 3.1 版开发,HTTPS 是在 HTTP 协议基础上实施 TLS 加密,所有网站以及其他部分 web 服务都使用该协议。因此,任何使用 HTTPS 的网站都使用 TLS 加密。

使用了 SSL/TLS 之后,因为数据被非对称加密手段加密了,即使被截获,也是获取不到信息的。

TLS 协议实现的功能有三个主要组成部分:加密、认证和完整性。

  • 加密: 隐藏从第三方传输的数据。
  • 身份验证: 确保交换信息的各方是他们所声称的身份。
  • 完整性: 验证数据未被伪造或篡改。

为什么 SSL/TLS 可以保证安全

网站或应用程序要使用 TLS,必须在其源服务器上安装 TLS 证书(由于上述命名混淆,该证书也被称为 SSL 证书),而 TLS 连接是通过一个称为 TLS 握手的流程启动的,在这个过程中用户设备会和服务器交换确定信息,这些信息包括要使用的 TLS 版本、密码套件、TLS 证书、会话密钥等等。

而在浏览器端,当用户访问服务器页面的时候,浏览器会检查服务器的 SSL/TLS 许可是不是可用的,不可用的话,会提醒用户,这个网站不安全,也就是访问的数据可能被黑客截获;此时用户可以根据判断来不访问这个界面;许可都齐全的话,便可以安全的进行数据交互。

具体来说,SSL/TLS 在工作流程中通过如下三个方面保证安全性:

  • 通过 CA 体系交换 public key
  • 通过非对称加密算法,交换用于对称加密的密钥
  • 通过对称加密算法,加密正常的网络通信

术语表

为了方便大家阅读,特在此章将全文涉及到的一些专业术语进行整理,整理此术语表供大家查阅。

简称 英文全称 中文全称
CA Certificate Authority / Certification Authority 证书颁发机构
SSL Secure Sockets Layer 安全套接字层协议
TLS Transport Layer Security 传输层安全性协议
PKI Public key infrastructure 公钥基础设施
PCA Private Certificate Authority 私有证书颁发机构,又名私有 CA
HTTP Hypertext Transfer Protocol 超文本传输协议
HTTPS Hypertext Transfer Protocol Secure 超文本传输安全协议
- Public key 公钥
- Private key 私钥
OSI Open Systems Interconnection 开放网络互联模型
TCP Transmission Control Protocol 传输控制协议
DTLS Datagram Transport Layer Security 数据包传输层安全性协议
mTLS Mutual Transport Layer Security 双向 TLS
DH Diffie-Hellman key exchange 迪菲-赫尔曼密钥交换
- premaster secret 预主密钥

TLS 相关协议详解

HTTPS 协议组成

HTTP 协议是用于从网络传送超文本数据到本地浏览器的传送协议,HTTPS 协议简单讲是 HTTP 的安全版,在 HTTP 协议的基础上加入 SSL 层。

其中,HTTP的端口号为80, HTTPS的端口号为443,两者均为应用层协议,在 OSI 七层模型的最上层。

Untitled

HTTPS 与 CA 证书

在 HTTPS 的工作流程中,一个重要的角色便是证书,他的正常运行需要有一个证书(CA 证书):由专门的证书机构颁发。在知道了 TLS 的握手流程后,我们来看看证书在其中所起到的作用。

当客户端向服务端发送请求,请求中会向服务器提供以下信息:客户端支持的协议版本,比如TLS 1.0 版,此后,服务器返回经过 CA 认证的数字证书,证书里面包含了服务器的 public key,接下来证书在客户端的工作流程如下:

  • 客户端读取证书中的相关的明文信息,采用相同的散列函数计算得到信息摘要,然后,利用对应CA的公钥解密签名数据,对比证书的信息摘要,如果一致,则可以确认证书的合法性,即公钥合法;
  • 客户端然后验证证书相关的域名信息、有效时间等信息;
  • 客户端会内置信任 CA 的证书信息(此处一般指顶级 CA 的自签根证书,包含公钥),如果 CA 不被信任,则找不到对应 CA 的证书,证书也会被判定非法;此外,客户端还会通过 OCSP 对证书状态进行查询;
  • 客户端在完成对数字证书的验证后,用自己浏览器内置的 CA 证书解密得到服务器的 public key;
  • 客户端用服务器的 public key 加密一个预主密钥(这个密钥将在之后结合随机数等信息被用于客户端和服务端各自生成用于网络通信的对称密钥),传给服务器。因为只有服务器有 private key 可以解密,所以不用担心中间人拦截这个加密数据而获取其中的密钥信息;
  • 服务器拿到这个加密的密钥,解密获取信息,再依据双方约定好的参数生成对称加密密钥,并以此和客户端完成接下来的网络通信;

关于 TLS 证书/CA 证书的更多细节,可以参见文章《奇妙的 SSL/TLS 证书》,本文不再深入探讨。

TLS/SSL 握手与密钥交换

HTTPS 连接建立过程和 HTTP 差不多,区别在于 HTTP(默认端口 80) 请求只要在 TCP 连接建立后就可以发起,而 HTTPS(默认端口 443) 在 TCP 连接建立后,还需要经历 SSL 协议握手,成功后才能发起请求。

Untitled

TLS 1.2 握手流程

在 TLS1.2 以前,需要2-RTT时间进行握手,我们具体来看每一步操作:

  1. 第1步:整个连接是从客户端向服务器发送“Client Hello”消息开始。该消息由加密信息组成,与此同时客户端也会将本身支持的所有密码套件(Cipher Suite)列表发送过去,包括支持的协议和支持的密码套件,也包含一个随机值或随机字节串。
  2. 第2步:响应客户端的“客户端问候”消息,服务器以“Server Hello”消息响应。此消息包含服务器已从客户端提供的 CipherSuite 中选择的 CipherSuite。服务器还会将其证书以及会话ID和另一个随机值一起发送。
  3. 第3步:客户端验证服务器发送的证书。验证完成后,它会发送一个随机字节字符串,也称为“预主密钥”,并使用服务器证书的公钥对其进行加密。客户端向服务器发送“ChangeCipherSpec”消息,通过会话密钥的帮助让它知道它将切换到对称加密。与此同时,它还发送“客户端已完成”消息。
  4. 第4步:一旦服务器收到预主密钥,客户端和服务器都会生成一个主密钥以及会话密钥(临时密钥)。这些会话密钥将用于对称加密数据。在答复客户端的“更改密码规范”消息时,服务器执行相同操作并将其安全状态切换为对称加密。服务器通过发送“服务器已完成”消息来结束握手。

在客户端和服务器之间进行了两次往返(2-RTT)以完成握手。 平均而言,这需要0.25秒到0.5秒之间的时间。而这只是握手过程,实际的数据传输还没有开始。我们绘制示意图如下解释如上流程:

Untitled

TLS 1.3 握手流程

TLS1.3 在握手上做了优化,只需要一次时延往返就可以建立连接(1-RTT),其握手基本步骤为:

  • 客户端问候:客户端发送客户端问候消息,内含协议版本、客户端随机数和密码套件列表。由于已从 TLS 1.3 中删除了对不安全密码套件的支持,因此可能的密码套件数量大大减少。客户端问候消息还包括将用于计算预主密钥的参数。
  • 服务器生成主密钥:此时,服务器已经接收到客户端随机数以及客户端的参数和密码套件。它已经拥有服务器随机数,因为它可以自己生成。因此,服务器可以创建主密钥。
  • 服务器问候和“完成”:服务器问候包括服务器的证书、数字签名、服务器随机数和选择的密码套件。因为它已经有了主密钥,所以它也发送了一个“完成”消息。
  • 最后步骤和客户端“完成”:客户端验证签名和证书,生成主密钥,并发送“完成”消息。
  • 实现安全对称加密:依据双方约定好的参数生成的对称加密主密钥,将被用在接下来客户端和服务端的网络通信中;

TLS 1.3 的核心宗旨是简单性。在新版本中,除去了 Diffie-Hellman(DH)密钥交换以外的所有密钥交换算法。简而言之,DH 算法(Diffie-Hellman 算法)可以保证在双方不直接传输原始密钥的情况下,完成双方密钥交换。

TLS 1.3 还定义了一组经过测试的 DH 参数,无需与服务器协商参数。由于只有一个密钥交换算法(具有内置参数)和少数支持的密码,因此设置 TLS 1.3 通道所需的绝对带宽比早期版本要少得多。示意图流程如下:

Untitled

基于 UDP 的 TLS 协议:DTLS

DTLS 介绍

DTLS 是基于 UDP 场景下数据包可能丢失或重新排序的现实情况下,为 UDP 定制和改进的 TLS 协议。

Untitled

DTLS 协议由两层组成: Record 协议 和 Handshake 协议

  1. Record 协议:使用对称密钥对传输数据进行加密,并使用 HMAC 对数据进行完整性校验,实现了数据的安全传输。
  2. Handshake 协议:使用非对称加密算法,完成 Record 协议使用的对称密钥的协商。

DTLS 与 TLS 握手差异

与 TLS 的握手流程相比,DTLS 的握手流程存在如下几点差异(左为 TLS 握手,右为 DTLS 握手):

Untitled

  1. HelloVerifyRequest 用于服务端对客户端实现二次校验;DTLS 的 RecordLayer 新增了 SequenceNumber 和 Epoch,以及 ClientHello 中新增了 Cookie,以及 Handshake 中新增了 Fragment 信息(防止超过 UDP 的 MTU),都是为了适应 UDP 的丢包以及容易被攻击做的改进;
  2. Certificate 是交换的证书,由协商后的算法确定是否需要传输;
  3. TLS 没有发送 CertificateRequest,这个也不是必须的,是反向验证即服务器验证客户端;当服务端要求验证客户端身份时,发起 CertificateRequest,此时客户端需要发送证书;
  4. ChangeCipherSpec 是一个简单的标记,标明当前已经完成密钥协商,可以准备传输;
  5. Finished 消息表示握手结束,通常会携带加密数据由对端进行初次验证。

DTLS 的握手防护、加密方式与应用场景

在实现机制上,DTLS 还存在几个特点,首先是握手防护机制,在这个机制中,除了上文说到的防止被攻击等在握手阶段引入的改进措施外,还有一个机制叫重传:

  • DTLS 每一方在每次握手中传送的第一个消息总是有 message_seq = 0。每当有新消息产生时,message_seq 的值就会增加1。
  • DTLS需兼容多种出错场景,出错时往往直接丢弃处理,而在 TLS 中,如果出错,则会中断连接;

以握手的第一阶段举例,客户端发送 Client Hello(不带 Cookie,区别于握手流程中的第二次 Client Hello)之后,启动一个定时器,等待服务端返回 HelloVerifyRequest,如果超过了定时器时间客户端还没有收到 HelloVerifyRequest,那么客户端就会知道要么是 Client Hello 消息丢了要么是 Hello Verify Request 消息丢了,客户端就会再次发送相同的 Client Hello 消息,即使服务端确实发送了 Hello Verify Request 还是收到了 Client Hello 消息,它也知道是需要重传,并再次发送 Hello Verify Request 消息,同样地,服务端也会启动定时器来等待下一条消息。

由于 DTLS 依赖 UDP,而 SSL/TLS 依赖 TCP,所以两者在加密方式上存在如下差异:

  1. SSL/TLS 不能独立解密单个封包,SSL/TLS 对于封包的认证需要序号作为输入,在 SSL/TLS 中并未直接传递序号,因为 TCP 是可靠的,所以 SSL/TLS 的两端各自维护自身的收发序号;
  2. DTLS 支持独立解密,其通过在每条记录中显式携带的序号作为解码的输入;此外,由于算法加解密的限制,DTLS所支持的加密算法为 TLS 的子集。

DTLS 主要被用在 WebRTC 协议中,以保证媒体传输的安全性。

客户端身份校验与 mTLS

在基础的 TLS 认证流程中,大量的场景都是确保用户访问的是真正的服务方,如:银行、电商网站等等,即保证用户不会被钓鱼网站或是中间人攻击,此时我们只需要在客户端侧对服务端身份进行校验。

SSL 连接中的客户端身份校验

在典型的 SSL 连接场景中,通过 HTTPS 连接到服务器的客户端会检查服务器的有效性,它会在启动 SSL 握手时检查服务器返回证书的有效性。但是,有时你可能希望将服务器配置为对与其连接的客户端进行身份验证。这样,你便可以只允许使用证书进行身份验证的用户访问 web 服务器上的资源。

启用客户端身份校验的两个基本步骤:

  1. 客户端需要获取、并安装经过 CA 认证的 SSL/TLS 证书
  2. 服务端需要开启客户端身份验证选项

Untitled

由于客户端安装证书的不方便性、成本高以及双因素身份验证的快速推行,客户端身份验证并没有得到广泛使用。

mTLS 介绍

很多时候,比如在一些支付场景下,我们和支付机构、商户构成的三者关系中,在商户和支付机构间需要保证相互的身份认证,以保证支付信息在两者间正常流转,这时便需要我们使用双向认证,即相互 TLS。

相互 TLS,简称 mTLS,是一种相互身份验证的方法。mTLS 通过验证他们都拥有正确的私人密钥来确保网络连接两端的各方都是他们声称的身份。他们各自的 TLS 证书中的信息提供了额外的验证。

mTLS 与 TLS 流程的区别

一个典型的 TLS 流程应该包含如下几步:

  1. 客户端连接到服务器
  2. 服务器出示其 TLS 证书
  3. 客户端验证服务器的证书
  4. 客户端和服务器通过加密的 TLS 连接交换信息

相比之下,mTLS 会在客户端验证服务器证书后加上几步,以保证服务端可以对客户端身份进行验证,并授予访问权限,一个完整的 mTLS 流程如下:

  1. 客户端连接到服务器
  2. 服务器出示其 TLS 证书
  3. 客户端验证服务器的证书
  4. 客户端出示其 TLS 证书
  5. 服务器验证客户端的证书
  6. 服务器授予访问权限
  7. 客户端和服务器通过加密的 TLS 连接交换信息

mTLS 的应用场景与安全性

由于公共互联网上亟待解决的问题是防止被访问的网站内容被篡改,保证用户不会访问到钓鱼网站;此外,再加上将 TLS 证书分发到所有终端用户设备上是非常困难的现状,mTLS 并没有被运用到整个互联网。mTLS 对于较小范围内的组织验证和通信非常有用,除了验证信息外,他还可以防止各种类型的攻击,比如在途攻击、网络钓鱼攻击以及恶意 API 请求等等。

mTLS 通常被用于零信任安全框架,以验证组织内的用户、设备和服务器。它也可以帮助保持 API 的安全。

HTTPS 与 Keyless SSL

虽然 HTTPS 可以解决传输的安全性但是引入了私钥的安全和管理问题。只要拿到了私钥,HTTPS 就如同虚设。尤其是在传统 CDN 加速场景下,需要将私钥证书同步给 CDN,无形中增加了风险,所以诞生了 Keyless 技术。这项技术可以使得客户在使用 CDN 进行 HTTPS 加速时保留其自身 SSL 的私钥,在仅有公钥的场景下顺利完成 SSL 握手。

在 Keyless 的作用下,服务端不解密密文,而是将经加密后的预主密钥(premaster secret)等数据打包发送给远端 key server,由其进行加工并返回数据;针对 DH 协商密钥的流程,服务端则负责将 DH 参数、服务端随机数、客户端随机数等数据传给 key server,由 key server 处理后返回 DH 数据以及证书等信息。

以 CloudFlare 为例,我们看看 Keyless 在部署时有设计哪些额外的流程以保证安全。为了使 Keyless SSL 安全,CloudFlare 边缘到 key server 的连接也需要安全。key server 可以为所有能够访问它的人提供私钥操作,就像一个密码数据库。保证只有 CloudFlare 可以访问 key server 来执行操作对 Keyless SSL 至关重要。

CloudFlare 通过相互认证的 TLS 机制来保证 CloudFlare 和 key server 之间的连接安全。在握手环节一章,我们提到了客户端对服务端的单方向身份认证,是通过验证 CA 证书来进行的,而后我们也提到了客户端身份校验,这在这里便派上了用场。在 TLS 双向认证中,客户端和服务端都由对方的证书并相互认证。

在 Keyless SSL 中,key server 仅允许携带 CloudFlare 内部签发的证书的连接。CloudFlare 使用我们自己签发的证书来进行双向认证。

在这里,我们以 RSA 为例,如下两图展示了在接入 Keyless 前后,TLS 握手过程的变化差异。

Untitled

Untitled

RFC 协议标准

本文介绍的各类协议均有对应的 RFC 标准,罗列于此供读者参考:

  1. TLS1.3 https://www.rfc-editor.org/rfc/rfc8446
  2. DTLS1.2 https://www.rfc-editor.org/rfc/rfc6347.html
  3. HTTPS https://www.rfc-editor.org/rfc/rfc2818.html
  4. MTLS https://www.rfc-editor.org/rfc/rfc8705

HTTPS 流量抓包与分析

利用 wireshark 我们可以对 https 流量进行抓包分析,下载地址见 https://www.wireshark.org/#download

操作与步骤

通过 Wireshark 我们可以很好的过滤 HTTPS 流量,比如如下常见的几个过滤条件:

// TLS加密传输数据的过滤器
ssl.record.content_type == 23  and tcp.dstport == 443

// TLS 建立连接
ssl.handshake.type == 1

// 在知道 IP 地址为A时的指定 TLS 流量
ip.addr == A && tcp.port == 443

但对于 HTTPS 流量,如果需要解密,我们还需要增加如下几个步骤来达成目的:

  1. 在终端打开你的 chrome 浏览器,并指定你的 SSL key 的 log 日志存放地址,假设地址为A;
  2. 在 WireShark 中,通过路径 Wireshark - Preferences - Protocols - TLS ,在 (Pre)-Master-Secret log filename 输入同样的地址 A,并保存;
  3. 然后通过第一步打开的浏览器访问 https 协议的网站地址,并在 wireshark 中指定 filter 例如 tls && ip.addr=1.1.1.1 来过滤指定 tls 流量;

通过 Wireshark 抓包,以一个 TLS1.2 版本的 ClientHello 消息报文内容为例,我们可以看到其中包含了客户端支持的 TLS 版本、加密套件、以及用于连接的 SNI 等信息

Untitled

同样的,以一个 TLS1.2 版本的建立连接为例,我们可以看到 Server 在返回 Server Hello 之后还返回了证书、Server Key Exchange 以及 Server Done 等信息

Untitled

应用与拓展场景

实现 Charles 抓包代理

用过抓包工具的人都知道,比如 Charles,Fiddler 是可以抓取 HTTPS 请求并解密的,它们是如何做到的呢?

简单来说,Charles 作为一个“中间人代理”,当浏览器和服务器通信时,Charles 接收服务器的证书,然后动态生成一张证书发送给浏览器,也就是说 Charles 作为中间代理在浏览器和服务器之间通信,所以通信的数据可以被 Charles 拦截并解密,这包括服务器证书公钥和 HTTPS 连接的对称密钥。

由于 Charles 更改了证书,浏览器校验不通过会给出安全警告,所以 Charles 可以正常工作的前提在于必须安装 Charles 的证书,使系统信任。

为开发环境启动 HTTPS

在本地开发功能模块时,可能有些 Web API 前置要求环境为 HTTPS,这要求我们在本地开发环境也能够配置 HTTPS,OpenSSL 是 SSL 和 TLS 协议的开放式源代码实现,使用它,我们可以在本地生成一个自签名证书,以方便开发。如下一行命令可以帮助我们生成一个 HTTPS 证书以及私钥:

openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

社区里有一个开源库叫 mkcert,可以更便捷的为你生成 TLS 证书,这里不深入介绍,感兴趣可以移步 https://github.com/FiloSottile/mkcert 查看更多。

注:为了能够正常使用,本地生成的证书需要被加入信任列表才能正常使用。

参考

  1. https://www.cloudflare.com/zh-cn/learning/ssl/what-happens-in-a-tls-handshake/
  2. https://tech.bytedance.net/articles/7166221771396349982
  3. https://blog.csdn.net/qzcsu/article/details/72861891
  4. https://tinychen.com/20200602-encryption-intro/
  5. https://comodosslstore.com/blog/what-is-ssl-tls-client-authentication-how-does-it-work.html
  6. https://web.dev/i18n/zh/how-to-use-local-https/
  7. https://blog.cloudflare.com/announcing-keyless-ssl-all-the-benefits-of-cloudflare-without-having-to-turn-over-your-private-ssl-keys/
  8. https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/
  9. https://tech.bytedance.net/articles/6915326021995200519
  10. https://www.cloudflare.com/zh-cn/learning/access-management/what-is-mutual-tls/
🔲 ☆

使用Caddy2托管静态博客

最近由于Cloudflare受到一些”干扰”,有网友提醒我的blog在国内有打不开的情况。不幸的是我的Blog + CDN都是托管给Cloudflare的,被无辜”殃及”了。再加上最近比较忙,blog也荒芜了快一年没打理,正好这个周末的晚上可以来折腾一下。

看了一下手上的吃灰的几个小鸡,发现竟然还有一台之前买的搬瓦工的小鸡,登录上去一看,好家伙,uptime 都659天了,稳啊! 好吧,就它了!接下来又是一波骚操作,从德国Contabo的主机rsync直接拷贝所有静态页面过来,速度还挺快。之前用的Nginx,这次打算再次换成Caddy Server,毕竟Caddy都出第二个版本了,自动更新SSL证书是比较能吸引我的地方。去官网研究了一下文档,还是决定用Docker来跑Caddy2,方便!

由于这个VPS只是用来放我的静态blog,所以也不用考虑多站点的问题,Caddyfile的配置简单到发指:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
https://xiaozhou.net
{
encode gzip
tls example.mail@gmail.com {
protocols tls1.2
}
root * /usr/share/caddy
file_server
}

http://www.xiaozhou.net
{
redir https://xiaozhou.net{url}
}

http://xiaozhou.net
{
redir https://xiaozhou.net{url}
}

配置里面有两个请求转发,把所有非HTTPS的请求都转发到HTTPS。然后,再准备一个shell脚本,用来运行Caddy2:

1
2
3
4
docker run -d --restart=always --name caddy -p 80:80 -p 443:443 \
-v /home/mysite:/usr/share/caddy/ \
-v $PWD/Caddyfile:/etc/caddy/Caddyfile \
caddy:2.4.5-alpine

容器直接暴露80端口和443端口到宿主机器即可。万事具备,只欠东风!去Cloudflare把域名解析过来,等生效,然后直接启动Caddy server。一切顺利,Caddy Server会在第一次启动的时候,自动申请LetsEncrypt的证书,后续也能自动renew。我懒啊,要的就是省心!

后续的流程,去GitHub改掉blog的自动部署流程,把部署的机器更新成现在的小鸡,打完收工!就这样,Blog又又又搬家了一次,从德国搬去了美国西海岸…… 唉……

🔲 ⭐

jAlbum升级JDK、Jetty和支持HTTP2

利用这个周六休息时间,将jAlbum代码升级了下。主要是想支持HTTP2,提升浏览器加载性能。升级过程中遇到一些问题,记录下:

1、alpn库的问题,jetty在配套不同的jdk版本时,有一些策略:见官网链接的说明:Jetty 9 and ALPN,jdk8使用一个单独的包,jdk9及以后的版本使用使用alpn的api,需要另外一个包。在不同的jdk环境下,依赖包有差异,不能混淆。

2、jar-with-dependencies 和 META-INF/services 冲突的问题。大概是jetty-http和jetty-http2包内都实现了同一个接口,而jvm只加载到了其中一个:
org.eclipse.jetty.http.Http1FieldPreEncoder
org.eclipse.jetty.http2.hpack.HpackFieldPreEncode
两个类都实现了同一个接口,使用了META-INF/servcies目录的机制。由于之前打包时,使用了将所有依赖包都抽取到一个独立jar包的做法,导致这个servcies目录下的同名文件只保留一个,最终http2的类无法加载成功。改用依赖包放在单独目录的方式,解决问题。

3、升级jdk到11之后,有几个原本是jdk自带的工具包(jaxb和anonations)被新版本jdk删除了,只能一一重新在pom.xml中添加回来。

本来支持http2是个比较简单的事情,由于这些库之间的互相依赖,折腾了比较久。具体修改:Commit记录。也编译了0.3.2版本放在版本下载表中。升级改造之后jAlbum、本站以及相关的子站点都全面支持HTTP2。

❌