# X.509 证书认证

X.509 是一种标准的公钥证书格式，广泛用于互联网的安全通信中。EMQX 支持使用 X.509 证书进行 TLS/SSL 连接以及客户端/服务器双向认证，以实现更高级别的安全性保障。

## 工作原理

EMQX 允许客户端使用 X.509 证书进行 TLS/SSL 连接，并支持将证书信息与客户端进行绑定，以实现 X.509 证书认证。其使用与工作流程如下：

1. 签发服务端证书，为 EMQX 启用 TLS/SSL，并设置其为[双向认证](../../network/emqx-mqtt-tls.md#启用双向认证)。
2. 签发客户端证书，将证书与私钥文件烧录到设备中，并使用其进行 TLS/SSL 连接。
3. 客户端将在 TLS 握手阶段发送证书给服务器，以证明其身份的合法性。
4. EMQX 收到客户端的证书后，会对证书进行验证，以确认客户端的身份。
5. 如果验证通过，服务器会继续完成 TLS 握手，建立安全连接。

连接成功后，EMQX 支持将证书信息映射到客户端属性，实现证书与客户端的绑定。除此之外，还可以搭配其他应用层的认证方式，如 [JWT](./jwt.md)、[密码认证](./pwoverview.md)，实现多种认证方式的组合。

## 特性与优势

- **安全性**：X.509 提供了一种安全可靠的认证机制，通过使用数字证书和公钥加密技术，确保了通信的机密性、完整性和身份验证。它可以防止未经授权的设备接入网络或进行恶意操作。

- **互操作性**：X.509 是一种通用的标准，被广泛支持和采用。许多物联网设备都支持 X.509 证书的使用，这使得设备之间的认证和安全通信更加简单和可靠。

- **可扩展性**：X.509 可以支持大规模的物联网部署。它提供了灵活的证书链和证书管理机制，可以适应复杂的物联网环境，并支持大量设备和实体的身份验证。

- **可信任的第三方验证**：X.509 证书通常由可信任的证书颁发机构（Certificate Authority）签发，这些 CA 经过严格的安全审查和验证。设备可以使用由受信任的 CA 签发的证书，确保其身份和证书的合法性。

- **强大的加密算法支持**：X.509 支持广泛的加密算法和密钥长度，包括常用的对称加密算法和非对称加密算法。这使得物联网设备可以使用强大的密码学算法来保护通信的安全性。

- **灵活的证书配置和管理**：X.509 具有灵活的证书配置和管理选项。设备可以根据需求选择适当的证书属性和扩展字段，以满足特定的物联网应用需求。此外，证书的吊销和更新也可以通过证书管理机制进行有效管理。

这些特性使得 X.509 成为物联网安全的理想选择，EMQX 提供了完整的 X.509 证书认证支持，可以帮助您轻松实现物联网设备的安全接入和通信。

## 启用 X.509 证书认证

X.509 证书认证其实就是 TLS/SSL 双向认证，您可以参考 [启用双向认证](../../network/emqx-mqtt-tls.md#启用双向认证) 进行配置。

::: tip
X.509 证书认证是在密码认证与 JWT 认证前执行的。
:::

## 证书信息映射

EMQX 支持将 X.509 证书信息映射为用户名或客户端 ID，以实现证书与客户端的绑定。您可以通过 Dashboard 或配置文件进行设置。

::: warning 映射对端证书字段时必须启用 mTLS

如果将 `peer_cert_as_username` 或 `peer_cert_as_clientid` 设置为非 `disabled` 的取值，对应的 SSL 监听器必须强制启用双向 TLS：

- `verify = verify_peer`
- `fail_if_no_peer_cert = true`
- `cacertfile` 指向您自己掌控的 CA 证书集合（不要信任公共 CA，因为它们可以为任意名称签发证书）

:::

如果未启用 mTLS，客户端可以在完全不出示证书的情况下完成连接，也可以出示一张 CN/DN 任意填写的自签名证书。EMQX 不会对其做校验，会直接将该 CN/DN 映射为用户名或客户端 ID。攻击者自选的 CN/DN 可以让客户端冒充任意身份；空的 CN/DN 则可能导致下游认证器（例如 HTTP 认证器）出现非预期行为。启用 mTLS 后，EMQX 会在映射之前直接拒绝握手。

::: tip

针对空用户名场景，可在监听器上同时设置 `listeners.{type}.{name}.enable_authn = quick_deny_anonymous`，这样当客户端的派生用户名为空时会被立即拒绝，不进入认证链。该设置是对 mTLS 的补充，但不能替代 mTLS，它无法防御伪造 CN/DN 的攻击。

:::

您可以使用对端证书中的 CN、DN 等字段或整个证书内容来作为用户名。目前支持的证书信息对应的释义如下：

- `cn`: 证书的 CN 字段
- `dn`: 证书的 DN 信息，格式为 `CN=xxx,OU=xxx,O=xxx,L=xxx,ST=xxx,C=xxx`
- `crt`: 证书的 DER 格式内容
- `pem`: DER 证书转换为 PEM 格式的内容
- `md5`: 取 DER 或 PEM 证书内容的 MD5 值

### PROXY 协议注意事项

如果在上游负载均衡器终止 TLS，并在 TCP 监听器上启用了 `proxy_protocol = true`，同样存在身份伪造风险：EMQX 会信任负载均衡器通过 PROXY v2 帧注入的 CN/DN。在此场景下安全使用证书字段映射，需满足以下条件：

- 负载均衡器自身必须执行 mTLS，并且只转发已验证的 CN/DN。
- 该监听器必须只能从受信任的负载均衡器访问。在 EMQX 中通过 `listeners.{type}.{name}.access_rules = ["allow <trusted-LB-CIDR>", "deny all"]` 进行限制，并结合网络层控制（防火墙、私有网络或 Unix socket）作为纵深防御。

任何能直接访问 PROXY 协议端口的攻击者，都可以伪造一个带任意证书字段的 PROXY v2 帧，从而冒充任意客户端。

### 通过 Dashboard 设置

1. 打开 Dashboard，进入**管理** -> **MQTT 配置**页面，选择**通用**选项卡。
2. 在 MQTT 配置中找到以下配置项进行修改：
   - **使用对端证书作为用户名**：将 X.509 证书信息映射为用户名。
   - **使用对端证书作为客户端 ID**：将 X.509 证书信息映射为客户端 ID。

3. 点击**保存修改**按钮完成配置，新连接的客户端将按照配置的方式进行信息映射。

### 通过配置文件设置

1. 打开配置文件 `base.hocon`，根据您的安装方式，可能位于 `./etc` 或 `/etc/emqx/etc` 目录。
2. 配置文件中默认没有 MQTT 配置，添加以下配置覆盖默认值：

  ```hocon
  mqtt {
    # 将证书信息作为客户端 ID
    peer_cert_as_clientid = "disabled" # "disabled" | "cn" | "dn" | "crt" | "pem" | "md5"
    # 将证书信息作为用户名
    peer_cert_as_username = "cn" # "disabled" | "cn" | "dn" | "crt" | "pem" | "md5"
  }
  ```

## 从证书主题备用名称初始化客户端属性

从 EMQX Enterprise 6.3.0 开始，当 TLS 连接在 EMQX 终结时，可以使用客户端证书中的主题备用名称（Subject Alternative Name，SAN）初始化客户端属性。支持的 SAN 类型包括 DNS 名称、IPv4 和 IPv6 地址、电子邮件地址和 URI。

在 `mqtt.client_attrs_init` 表达式中使用 `cert_san.dns`、`cert_san.ip`、`cert_san.email` 和 `cert_san.uri`。这些变量都是数组，需要使用 `nth()` 或 `join_to_string()` 等 Variform 函数生成客户端属性值。配置方法和示例参见[使用证书主题备用名称初始化客户端属性](../../../develop/client-attributes/client-attributes.md#使用证书主题备用名称初始化客户端属性)。

`peer_cert_as_username` 和 `peer_cert_as_clientid` 不支持提取 SAN。要在认证、授权或其他支持客户端属性的功能中使用 SAN，需要先将其保存为客户端属性。
