前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HTTP 安全通信保障:TLS、身份验证、授权

HTTP 安全通信保障:TLS、身份验证、授权

作者头像
小草学习屋
发布2023-11-22 09:51:49
4020
发布2023-11-22 09:51:49
举报
文章被收录于专栏:小草学习屋小草学习屋

对于交易支付相关的网络服务,需要保障安全、私密的网络通信。此时需要依赖 TLS 、身份验证和授权机制。我们先来了解基本概念。

TLS

TLS(Transfer Layer Security) 指传输层安全协议,它包括记录协议(例如 TCP )和握手协议,在下文中仅关注握手协议。

它的一种常见用法是和 HTTP 结合使用成为 HTTPS 。 HTTPS 的 S 还可以指代 SSL(Secure Sockets Layer),它是 TLS 的前身,目前也会用 SSL 指代 TLS。

那么,TLS 是如何在不可信的网络环境中实现安全地通信的呢?

首先,在建立连接的过程(即握手),完成密钥协商和身份验证。连接建立后,在每次请求中,使用密钥对数据加密来保证数据的保密性;使用签名和验签保证数据的完整性。

TLS 协议有1.1、1.2、1.3,当前使用的主流是 1.2。我们推荐使用最新的 TLS 1.3,它修复了 1.2 中的安全漏洞问题。

下面我们将从 TLS 1.1 开始了解整个 TLS 的演变过程。

TLS 1.1

下图是完整的握手流程:

TLS1.1.png
TLS1.1.png

* 表示的消息是可选发送的。

第一步:Client 向 Server 发送 ClientHello 消息。消息包括生成密钥的随机数1。 第二步:Server 发送 ServerHello 消息。消息包括:

  • 生成密钥的随机数2。
  • Certificate(服务端证书):包含签名算法、公钥等信息。
  • ServerKeyExchange(服务端密钥交换信息):包括密钥交换算法(RSA 或 DH ),仅当服务端证书信息不足以让客户端完成密钥协商时,才会补充发送。
  • CertificateRequest(证书请求):当服务端需要客户端提供证书时,发送此消息。包括消息可供选择的算法等。

第三步:Server 发送 SeverHelloDone 消息。消息包括 ServerHello 完成的关联数据。 第四步:Client 收到 ServerHelloDone 消息,验证服务端证书有效性。然后发送以下消息内容:

  • Certificate(客户端证书):仅当服务端发送证书请求消息时发送。
  • ClientKeyExchange(客户端密钥交换信息):生成密钥的最后一部分信息。如果密钥交换算法为 RSA ,则为使用服务端证书中的公钥加密后的随机数3;如果为 DH 算法则为 DH 参数。
  • CertificateVerify(客户端证书验证):消息为使用客户端证书对应的私钥签名。仅当发送了客户端证书时发送,以供服务端验证客户端证书。
  • 完成:客户端在更改了密钥规范信息后,此时客户端已具备生成密钥的算法和生成信息,生成密钥。 然后使用密钥加密并发送完成消息。

第五步:服务端接收到第四步消息,客户端身份和消息验证通过,生成密钥并使用密钥加密并发送完成消息。

以上就是 TLS 握手的完整流程。简单来说,就是客户端和服务器交换随机数完成密钥协商,通过签名和验签完成身份认证。

TLS 1.2

TLS 1.2 的握手流程和 TLS 1.1 完全一致:

TLS1.2.png
TLS1.2.png

相对 TLS 1.1,TLS 1.2 主要收紧限制了密钥协商中使用的算法,使用更新的安全算法。例如使用 SHA256 替换 MD5/SHA1。

TLS 1.3

TLS 1.3 是一个不向下兼容的协议,它极大地提高了通信安全和简化流程,是我们了解的重点。它的主要改进点如下:

  • 已支持的对称加密算法中,仅保留 AEAD 类型的算法;更改密码套件概念
  • 添加 0-TTR 模式
  • 提供向前保密
  • ServerHello 后的消息全部加密

下图是完整的握手流程:

TLS1.3.png
TLS1.3.png

握手流程简化成了3步:KeyExch(密钥交换)、Server Params(生成服务器参数)、Auth(身份验证)。

这三步中有很多可选参数,根据密钥交换模式不同选择传输。密钥交换支持 (EC)DHE、PSK-only、PSK with (EC)DHE。我们先来看这三种模式的含义。

密钥交换模式为 (EC)DHE

DH(Diffie–Hellman key exchange),即 Diffie–Hellman 密钥交换,是一种在公共通道中安全交换密钥的数学方法。假设通信为 a、b,基于 DH 生成密钥的流程如下:

  1. a、b 约定参数 p、q(用于生成g)、g。
  2. a、b 分别生成随机数作为私钥 xa、xb。
  3. a 根据 g ^ xa mod p 生成公钥 ya,b 根据 g ^ xb mod p 生成公钥 yb。
  4. a 根据 (yb ^ xa) mod p 生成统一变量 zz,b 根据 (ya ^ xb) mod p 生成统一变量 zz。
  5. 双方分别得到 zz,根据约定算法计算得到密钥。

整个过程通过自己的私钥,对方的公钥以及 p、q、g 参数、约定的密钥计算算法,就可以生成密钥。第三方需要计算得到私钥很困难,需要解决离散对数问题。

DHE(Diffie-Hellman Ephemeral)是临时 DHE,临时指的是公私钥对,每一次使用双方都会重新生成公私钥对,因此每一次都能计算得到不同的密钥。

这样的好处是每个连接都能生成不同密钥,当前连接的密钥泄漏,不会影响在此之前建立的连接。这个特性就叫 FS(Forward Secrecy)前向保密

EC(Elliptic Curve)指基于椭圆曲线,椭圆曲线密码学是一种公钥计算方法,它把公私钥作为椭圆上的一个点,指定私钥和椭圆曲线参数能计算得到公钥。使用它的好处是能提高密钥生成效率和加强安全性。

因此,(EC)DHE 的含义为 (基于椭圆曲线密码学得到公私钥的)临时 DH 算法。EC 是可选的。

密钥交换模式为 PSK-only

PSK(Pre-shared key)即预共享密钥,它可以在连接建立之前通过某种安全通道交换,例如离线部署;也可以在新的连接中使用上一次连接中设定的 PSK ID 来恢复使用上一次连接的 PSK。

PSK-only 即指只使用 PSK 的密钥交换模式,密钥只基于 PSK 生成。

使用它的好处是能实现 零往返时间(0-RRT) 模式。基于 PSK 建立的连接,客户端可以在 ClientHello 中就发送数据。同时使用 PSK 加密数据,验证服务端身份是否合法。

虽然这种模式可以节省时间,但是有一定的安全限制。

密钥交换模式为 PSK with (EC)DHE

PSK with (EC)DHE 即结合 (EC)DHE 的 PSK 。PSK 和 (EC)DHE 的 zz 参数一起作为参数生成密钥。这样做的好处是,相比 PSK-only,能够保证前向安全。

握手流程

TLS1.3.png
TLS1.3.png

现在来看握手流程。

第一步,Client 向 Server 发送 ClientHello 消息。包括:

  • 密钥共享(key_share):若密钥交换模式包含 (EC)DHE,则包括客户端的 (EC)DHE 使用的参数信息,例如 p、q、g,公钥。客户端也可以发送空内容,让服务端选择参数。
  • 签名算法(signature_algorithms):在 TLS 1.3 中,仅允许 RSA、ECDSA、EdDSA 算法。
  • PSK 交换模式(psk_key_exchange_modes):密钥交换模式为 PSK-only 时,值为 psk_key;密钥交换模式为 PSK with(EC)DHE 时,值为 psk_dhe_key
  • PSK

第二步,Server 向 Client 发送 ServerHello 消息。包括:

  • 密钥共享(key_share):服务端的 (EC)DHE 使用的参数。例如公钥。
  • PSK
  • 加密扩展(EncryptedExtensions):对不需要确定加密参数的 ClientHello 扩展的响应。这是使用 server_handshake_traffic_secret 加密的数据。
  • 证书请求(CertificateRequest):当服务端需要客户端提供证书时,发送此消息。包括消息可供选择的算法等。
  • 服务端证书(Certificate)
  • 服务端证书验证(CertificateVerify):使用服务端证书对应的私钥签名。以供客户端验服务端证书。
  • 完成(Finished)消息:该消息为一个 MAC, server_handshake_traffic_secret 作为密钥,使用 HMAC 计算得出。客户端需要校验该消息是否合法。
  • 应用消息(Application Data):请求的应用消息。

第三步,客户端验证服务端的身份。它会发送如下消息:

  • 客户端证书(Certificate):当服务端请求客户端提供证书时发送。
  • 客户端证书验证消息(CertificateVerify):使用客户端证书对应的私钥签名。以供服务端验证客户端证书。
  • 完成(Finished)消息:该消息为一个 MAC, client_handshake_traffic_secret 作为密钥,使用 HMAC 计算得出。服务端需要校验该消息是否合法。
  • 应用消息(Application Data):请求的应用消息。

至此,握手完成。握手流程中出现了一些密钥,用于加密数据或者生成 MAC。这也是 TLS 1.3 的一个特性:将身份验证、密钥交换机制中加密和生成 hash 值的密钥分开,以获得更高的安全性。

我们来了解下这些密钥是如何生成的。

密钥生成机制和方法

TLS 1.2 使用的是 KDF(Key Derivation Function) 密钥派生函数来得到密钥。它通过使用伪随机函数来获取所需格式的密钥。

TLS 1.3 使用的是 HKDF(HMAC KDF)[RFC5869],即基于 HMAC 的 KDF 算法。它的原理是先提取再拓展。先采用输入的密钥生成材料并从中提取固定长度的伪随机密钥,然后将伪随机密钥拓展为几个额外的伪随机密钥。在 TLS 1.3 中,这些伪随机密钥就被用于身份验证、加密等不同用途。

HKDF 的两个步骤分别为 HKDF-Extract 和 Derive-Secret。

HKDF-Extract 的 计算方法如下图:

代码语言:javascript
复制
   HKDF-Extract(salt, IKM) -> PRK
   PRK = HMAC-Hash(salt, IKM)

salt 为可选参数,使用盐可以提高 HKDF 算法的强度。 IKM(input keying material)为输入密钥材料,它可以为空输出 PKR(伪随机密钥)。

Derive-Secret 的计算方法如下图:

derive-secret.png
derive-secret.png

它的输入为 Secret(密钥)、Label。

下图是 TLS 1.3 的密钥派生体系:

key-structure.png
key-structure.png
  • HKDF-Extract 从上方获取 salt,从左边获取 IKM,输出内容在中间,输出名称在右边。
  • Derive-Secret 的 Secret 参数由传入箭头指示。例如,Early Secret 是用于生成 client_early_traffic_secret 的 Secret。
  • 0 表示输入长度为0的参数。

Derive的输入原材料为 PSK 和 (EC)DHE 中生成的 ZZ。

第一步, PSK 作为输入密钥, 和长度为0的盐通过 HKDF-Extract 生成 Early Secret。

第二步,将 Early Secret 和固定字段、ClientHello 结合,通过 Derive-Secret 方法计算得到 binder_key、client_early_traffic_secret、early_exporter_master_secret。

第三步, (EC)DHE 的 ZZ 作为输入密钥,和 Derive-Secret(Early Secret, "derived", "") 的计算值作为盐,通过 HKDF-Extract 计算得到 Handshake Secret。Handshake Secret 和固定字段、ClientHello、ServerHello 结合,通过 Derive-Secret 方法计算得到 client_handshake_traffic_secret、server_handshake_traffic_secret。

第四步,Derive-Secret(Handshake Secret, "derived", "") 作为盐通过 HKDF-Extract 得到 Master Secret。Master Secret 和固定字段、ClientHello 、server Finished 等得到4个 Secret。

上述过程用于握手和通信的密钥如下:

traffic-key.png
traffic-key.png

client_early_traffic_secret 加密 0-RTT 的数据; sender_handshake_traffic_secret 加密握手过程的数据; sender_application_traffic_secret_N 加密通信过程的应用数据。

以上是 TLS 1.3 的大概流程。

TLS 能够保障建立安全隐私的网络通道。基于 TLS,客户端和服务器需要通过身份验证来授权,从而完成获取资源。我们先来看身份验证和授权的方式。

身份验证

客户端在请求服务器获取资源前,第一步是证明自己的身份,服务端再根据客户端的身份授权。证明自己的身份,即身份验证(Authentification)

身份验证大部分是单向的,由服务端直接或依赖第三方来验证客户端的身份。基于互不信任原则,也可以使用双向验证,即客户端和服务端互相验证。

在 HTTP 请求中,使用凭据验证身份。凭据可以是静态或动态生成的,它随着每次请求传输。常见的凭据中,静态的包括用户密码、API 密钥等;动态的包括数字签名。

  • 用户密码:最不安全的一种凭据,一般不会使用这种方式。凭据被窃取即意味着用户信息被窃取。
  • API 密钥:较为常见的身份验证凭据。这是服务端提供与客户端唯一对应的 API 密钥。
  • 数字签名:基于非对称密钥体系,使用私钥生成签名,公钥验证签名。

从不可抵赖性以及被窃取后可能造成的严重程度来看,凭据选择的优先级为数字签名 > API 密钥 > 用户密码。

授权

授权(Authorization)是指向经过身份验证的参与方授予执行某项操作的权限的操作。 授权的核心是授权凭据。

服务端可以直接或依赖第三方来授权客户端。直接授权使用的凭据和身份验证凭据一样,它结合内部授权机制实现。第三方授权通过第三方授权服务器获取授权凭据,主要依赖于采用 OAuth 2.0 标准的第三方实现。

OAuth 2.0

OAuth 2.0 [RFC6749] 是一个行业标准的授权协议。我们需要了解4个角色、2个资源、3个流程。

4个角色为Client(客户端)、 Resource Owner(资源拥有者)、Authorization Server(授权服务器)、Resource Server(资源服务器)。

2个资源分别为 Authorization Grant(授权授予)、Access Token(访问令牌)。

3个流程如下图:

OAuth2.0.png
OAuth2.0.png

第一步,客户端先向资源拥有者发送授权请求,获取授权授予。

第二步,客户端向授权服务器发送授权授予,获取资源的访问令牌。

第三步,客户端向资源服务器发送访问令牌,获取受保护的资源。

OAuth 2.0 中的访问令牌就是授权凭据。获取访问令牌有4种方式:

  • 授权码方式:通过授权码请求授权服务器获取令牌。
  • (授权码)隐藏式:无需授权码,客户端请求授权服务器获取令牌给前端。适用于请求服务没有后端服务的情景。
  • 密码式:通过用户密码请求授权服务器获取令牌。
  • 凭证式:通过 client_id 和 client_secret 请求授权服务器获取令牌,适用于命令行场景。

出于安全考虑,推荐使用授权码和凭据式。

HTTP 身份验证和授权方案

HTTP 提供了一个主流的身份验证和授权框架 [rfc7235],它的主要流程如下(图来自 HTTP authentication):

http-auth.png
http-auth.png

客户端需要在 HTTP 头部 Authorization 中放入凭据。若凭据无效,服务器会返回 401 Unauthorized;若授权凭据有效但权限不足以访问给定资源,服务器会返回 403 Forbidden。

凭据有几种类型,上面的 Authorization 头中的 Basic 就指基础类型,对凭据 Base64 编码。其他的类型还有:

  • Bearer: 基于 OAuth 2.0,表示 OAuth 2.0 的令牌。
  • Digest:Basic的增强版,对凭据使用 SHA-256 或 MD5 生成 HASH 值。
  • HOBA:HTTP Origin-Bound Authentication,凭据为共享密钥签出的数字签名。
  • Mutual:基于双向认证,凭据为分别计算得到的共同密钥计算得到的数字签名。
  • AWS4-HMAC-SHA256:AWS 服务的特定类型。

在此方案中,身份验证和授权都是依靠同一个凭据完成的,该凭据被放在 Authorization 。在其他实现中,也可以放在包体或者 URL。**出于安全考虑,推荐凭据放在 Authorization 头部或者包体。 **

实现

了解了身份验证和授权的基本概念和方式,我们来看支付网关实际是怎么做的。

国外主流支付网关的做法是基于 OAuth 2.0 来验证身份和授权,国内主流支付网关的做法是基于数字签名来验证身份和授权。

基于 OAuth 2.0 和 HTTP 身份验证授权框架

PayPal 就是基于 OAuth 2.0 和 HTTP 身份验证授权框架实现的典型例子。

PayPal 使用凭据式获取 access token 。获取 token 后,在后续请求中,结合 HTTP 身份验证框架,将 token 设置在 Authorization 头,向资源服务器请求。

代码语言:javascript
复制
graph LR
    A[Client] -->| client ID: Client Sercret | B(Authorization Server)
	    B -->| access token | A	
代码语言:javascript
复制
graph LR
A[Client] --> | Authorization: Bearer access token | B(Resource Server)

基于数字签名

微信支付和支付宝都是基于数字签名实现身份验证和授权的。

以微信支付为例:

商户在微信支付的商户平台获取商户公钥、私钥、微信支付平台证书,在向微信支付请求时,使用商户私钥对请求按照特定规则签名,并放在 Authorization 头中。微信支付返回时,会使用微信支付平台私钥对返回签名,并放在返回的 Authorization 中。

数字签名除了有身份验证的能力,还能保证消息的完整性。一旦消息被篡改了,计算得到的签名和消息体就会对应不上。

代码语言:javascript
复制
graph LR
A[商户] --> | Authorization: 认证类型 签名 | B(微信支付)
B[微信支付] --> | Authorization: 认证类型 签名 | A(商户)

参考文档

wiki

rfc

其他

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • TLS
    • TLS 1.1
      • TLS 1.2
        • TLS 1.3
          • 密钥交换模式为 (EC)DHE
          • 密钥交换模式为 PSK-only
          • 密钥交换模式为 PSK with (EC)DHE
          • 握手流程
      • 身份验证
      • 授权
        • OAuth 2.0
          • HTTP 身份验证和授权方案
          • 实现
            • 基于 OAuth 2.0 和 HTTP 身份验证授权框架
              • 基于数字签名
              • 参考文档
                • wiki
                  • rfc
                    • 其他
                    相关产品与服务
                    多因子身份认证
                    多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档