259 lines
14 KiB
Markdown
259 lines
14 KiB
Markdown
---
|
||
title: "身份服务 API"
|
||
weight: 40
|
||
type: docs
|
||
---
|
||
|
||
{{< boxes/warning >}}
|
||
本页面的翻译未经核对,可能存在翻译质量不佳、错翻、漏翻等情况。您可以在 <a href="https://codeberg.org/wholetrans/docs-matrix-spec">Forgejo 存储库</a> 打开 Issue、提交 Pull Request 或<a href="mailto:errata@wholetrans.org">邮件联系</a>我们提出改进建议和参与翻译与核对。
|
||
{{< /boxes/warning >}}
|
||
|
||
|
||
Matrix 的客户端-服务器与服务器-服务器 API 主要使用 Matrix 用户标识符。在某些情况下,我们需要以其他(“第三方”)标识符,或“3PID”(如电子邮件地址或电话号码)来引用用户。本身份服务规范描述了如何建立、验证和使用第三方标识符与 Matrix 用户标识符之间的映射。理论上,本规范可适用于任意 3PID,但实际上目前仅针对电子邮件地址和电话号码进行了具体实现。
|
||
|
||
## 基本原则
|
||
|
||
身份服务器的目的是验证、存储并响应有关用户身份的问题。具体来说,它存储如下关联:“标识符 X 与标识符 Y 代表同一用户”,其中这些身份可存在于不同系统(如电子邮件地址、电话号码、Matrix 用户 ID 等)中。
|
||
|
||
身份服务器拥有若干私钥-公钥对。当被查询某项关联时,它会使用其私钥对该关联的详细信息进行签名。客户端可通过验证身份服务器公钥的签名,来校验关于关联的声明。
|
||
|
||
通常情况下,身份服务器被视为可靠的权威。它们并不总能提供已验证关联的证据,但会声称已完成验证。具体信任哪台身份服务器,由客户端自行决定。
|
||
|
||
3PID 类型详见[3PID 类型](/appendices#3pid-types)附录。
|
||
|
||
## API 标准
|
||
|
||
Matrix 身份服务器通信的强制基线是通过 HTTP API 交换 JSON 对象。通信必须使用 HTTPS。
|
||
|
||
所有 `POST` 和 `PUT` 端点(出于历史原因,[`POST /_matrix/identity/v2/account/logout`](#post_matrixidentityv2accountlogout) 除外)都要求客户端在请求体中提交一个(可能为空的)JSON 对象。对于带有 JSON 请求体的请求,客户端应提供 `Content-Type: application/json` 头,但这非强制要求。
|
||
|
||
同样,所有端点都需返回 JSON 对象。服务器返回 JSON 时,必须包括 `Content-Type: application/json` 响应头。
|
||
|
||
所有请求或响应中的 JSON 数据,必须采用 UTF-8 编码。
|
||
|
||
### 标准错误响应
|
||
|
||
若在 Matrix API 层发生错误,必须返回“标准错误响应”。其格式为如下 JSON 对象:
|
||
|
||
```json
|
||
{
|
||
"errcode": "<error code>",
|
||
"error": "<error message>"
|
||
}
|
||
```
|
||
|
||
`error` 字符串为人类可读的错误信息,通常描述出错原因。`errcode` 字符串为唯一字符串,便于处理错误信息,如 `M_FORBIDDEN`。依据错误类型,可能含有其他键,但 `error` 和 `errcode` 两个键必须始终存在。
|
||
|
||
部分标准错误码如下:
|
||
|
||
`M_NOT_FOUND`
|
||
请求的资源无法找到。
|
||
|
||
`M_MISSING_PARAMS`
|
||
请求缺少一个或多个参数。
|
||
|
||
`M_INVALID_PARAM`
|
||
请求包含一个或多个无效参数。
|
||
|
||
`M_SESSION_NOT_VALIDATED`
|
||
Session 尚未验证。
|
||
|
||
`M_NO_VALID_SESSION`
|
||
根据提供参数找不到相关 Session。
|
||
|
||
`M_SESSION_EXPIRED`
|
||
Session 已过期,需重新创建。
|
||
|
||
`M_INVALID_EMAIL`
|
||
提供的电子邮件地址无效。
|
||
|
||
`M_EMAIL_SEND_ERROR`
|
||
发送邮件时出错。通常发生在验证给定邮箱所有权时。
|
||
|
||
`M_INVALID_ADDRESS`
|
||
提供的第三方地址无效。
|
||
|
||
`M_SEND_ERROR`
|
||
发送通知时出错。通常见于验证第三方地址所有权时。
|
||
|
||
`M_UNRECOGNIZED`
|
||
请求中包含未识别的值,如未知的 token 或 medium。
|
||
|
||
当服务器无法理解请求时,也会使用此响应。若端点未实现,返回 HTTP 状态码 404;若实现了但使用了错误的 HTTP 方法,返回 405。
|
||
|
||
`M_THREEPID_IN_USE`
|
||
第三方标识符已被他人使用。该错误通常会包含额外的 `mxid` 字段,以标明该 3PID 的所有者。
|
||
|
||
`M_UNKNOWN`
|
||
发生未知错误。
|
||
|
||
## 隐私
|
||
|
||
身份信息关系隐私敏感。身份服务器存在的目的是提供身份信息,但访问应受到限制,以避免泄露潜在的敏感数据。尤其应避免构建大规模的身份关联网络。因此,API 通常允许将 3PID 映射到 Matrix 用户身份,但禁止反向映射(即不能查询某 Matrix 用户 ID 关联有哪些 3PID,也不能批量获取一个 3PID 关联的全部身份)。
|
||
|
||
## Web 浏览器客户端
|
||
|
||
部分客户端可能在 Web 浏览器或类似环境下运行。此时,身份服务器应响应预检(pre-flight)请求,并在所有请求中返回跨域资源共享(CORS)头。
|
||
|
||
当客户端以 OPTIONS 请求访问服务器时,服务器需返回对应路由的 CORS 头。建议服务器所有请求返回以下 CORS 头:
|
||
|
||
Access-Control-Allow-Origin: *
|
||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
||
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization
|
||
|
||
## API 版本检查
|
||
|
||
{{% http-api spec="identity" api="versions" %}}
|
||
|
||
## 认证
|
||
|
||
身份服务 API 的大多数端点都要求认证,以确保请求用户已接受所有相关政策,并有权限发起请求。
|
||
|
||
身份服务器采用类似 Client-Server API 的访问令牌方案进行用户认证。身份服务器发放的访问令牌不能用于认证 Client-Server API 请求。
|
||
|
||
访问令牌可通过请求头以 Bearer 方式提供:`Authorization: Bearer TheTokenHere`。
|
||
|
||
客户端也可以(但不推荐)通过查询字符串参数提供访问令牌:`access_token=TheTokenHere`。为避免令牌泄漏到访问日志或 HTTP 日志,不推荐客户端再采用这种方式。
|
||
|
||
身份服务器必须同时支持这两种方式。
|
||
|
||
{{% boxes/note %}}
|
||
{{% changed-in v="1.11" %}}
|
||
通过查询字符串参数传递访问令牌已被弃用。
|
||
{{% /boxes/note %}}
|
||
|
||
若缺少或认证凭据无效,HTTP 响应为 401,错误码为 `M_UNAUTHORIZED`。
|
||
|
||
{{% http-api spec="identity" api="v2_auth" %}}
|
||
|
||
## 服务条款
|
||
|
||
身份服务器建议配置服务条款(或类似政策),以确保用户同意服务器处理其数据。为此,身份服务器可以对几乎所有需认证的 API 端点返回 HTTP 403 和错误码 `M_TERMS_NOT_SIGNED`。该状态表明,用户需接受最新服务条款后才能继续操作。
|
||
|
||
所有支持认证的端点都可能返回 `M_TERMS_NOT_SIGNED` 错误。收到此错误后,客户端应调用 `GET /terms` 获取服务器提供的服务条款,并与用户的 `m.accepted_terms` 账号数据(下文介绍)进行比较,再向用户展示尚未接受的服务条款,并提供同意的选项。用户选择后(如适用),客户端调用 `POST /terms` 提交已接受的条款。服务器不可假定客户端会一次性提交所有待同意的条款,客户端也不可假定服务器接收到这些条款后就不会再次响应 `M_TERMS_NOT_SIGNED`。用户刚同意的条款会追加到 `m.accepted_terms`。
|
||
|
||
{{% event event="m.accepted_terms" %}}
|
||
|
||
{{% http-api spec="identity" api="v2_terms" %}}
|
||
|
||
## 状态检查
|
||
|
||
{{% http-api spec="identity" api="v2_ping" %}}
|
||
|
||
## 密钥管理
|
||
|
||
身份服务器拥有若干长期公钥-私钥对。命名方式为 `算法:标识符`,如 `ed25519:0`。签名关联时,遵循标准的[签名 JSON](/appendices#signing-json)算法。
|
||
|
||
身份服务器还可以管理一些短期公私钥对,这些密钥的用途和生命周期可与长期密钥不同。
|
||
|
||
{{% http-api spec="identity" api="v2_pubkey" %}}
|
||
|
||
## 关联查询
|
||
|
||
{{% http-api spec="identity" api="v2_lookup" %}}
|
||
|
||
### 客户端行为
|
||
|
||
在执行查询前,客户端应优先请求 `/hash_details` 端点,确定服务器支持哪些算法(详见下文)。客户端获取该信息后,形成相应的 `/lookup` 请求以从服务器获取已知绑定关系。
|
||
|
||
客户端必须至少支持 `sha256` 算法。
|
||
|
||
### 服务器行为
|
||
|
||
服务器收到 `/lookup` 请求后,将查询与其已知的绑定比较,必要时对本地存储的标识进行哈希以确定是否与请求完全匹配。
|
||
|
||
服务器必须至少支持 `sha256` 算法。
|
||
|
||
### 算法
|
||
|
||
部分算法在规范中有定义;如有其他需求,客户端和服务器可通过 `/hash_details` 协商格式。
|
||
|
||
#### `sha256`
|
||
|
||
客户端与服务器必须至少支持此算法,并且它也是推荐用于查询的算法。
|
||
|
||
采用此算法时,客户端将查询项转换为以空格分隔的字符串,格式为 `<address> <medium> <pepper>`。`<pepper>` 取自 `/hash_details`,`<medium>` 通常为小写 `email` 或 `msisdn`,`<address>` 即要查询的 3PID。例如,若客户端要查询 `alice@example.org` 的绑定关系,格式为 `alice@example.org email ThePepperGoesHere`。
|
||
|
||
{{% boxes/rationale %}}
|
||
将 medium 与 pepper 附加到 address,可避免每个 3PID 前缀相同,提升哈希函数抗预计算攻击能力。
|
||
{{% /boxes/rationale %}}
|
||
|
||
每条格式化字符串经 SHA-256(参见 [RFC 4634](https://tools.ietf.org/html/rfc4634))处理后,结果用 URL-Safe [Unpadded Base64](/appendices#unpadded-base64) 编码(与 [room version 4 的事件 ID 格式](/rooms/v4#event-ids) 类似)。
|
||
|
||
如使用 pepper `matrixrocks`,示例查询如下:
|
||
|
||
"alice@example.com email matrixrocks" -> "4kenr7N9drpCJ4AfalmlGQVsOn3o2RHjkADUpXJWZUc"
|
||
"bob@example.com email matrixrocks" -> "LJwSazmv46n0hlMlsb_iYxI0_HXEqy_yj6Jm636cdT8"
|
||
"18005552067 msisdn matrixrocks" -> "nlo35_T5fzSGZzJApqu8lgIudJvmOQtDaHtr-I4rU7I"
|
||
|
||
哈希后的字符串集作为 `/lookup` 请求体内的 `addresses` 数组。注意,使用的 pepper 必须通过 `/lookup` 的 `pepper` 参数一并提交。
|
||
|
||
#### `none`
|
||
|
||
此算法在身份服务器上执行明文查询。若因安全原因不宜传播明文标识,一般不推荐用该算法,但在某些场景(如基于 LDAP 的身份服务器)无法使用哈希,因此允许(或可选地,客户端)采用该算法查询。
|
||
|
||
与 `sha256` 类似,客户端将查询项格式化为 `<address> <medium>` 的空格分隔字符串,不含 `<pepper>`。例如,要查询 `alice@example.org` 的绑定,格式为 `alice@example.org email`。
|
||
|
||
格式化字符串作为 `/lookup` 请求体内的 `addresses`。注意仍需提供 `pepper`(以保证客户端先正确查询了 `/hash_details`)。
|
||
|
||
### 安全性注意事项
|
||
|
||
{{% boxes/note %}}
|
||
请参考 [MSC2134](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2134-identity-hash-lookup.md),其中详细阐述了本节规范的安全考量。此处仅简述规范设计的高层原因。
|
||
{{% /boxes/note %}}
|
||
|
||
通常,/lookup 端点用于客户端拥有某 3PID,但希望获取对应的 Matrix 用户 ID 的场景。客户端常在邀请新用户入群或遍历通讯录查找未发现的 Matrix 用户时,用到此接口。恶意身份服务器若能收集到这些明文数据,可能滥用之。为保护未关联 Matrix ID 的 3PID 用户隐私,规范尽量提升批量收集 3PID 的难度。
|
||
|
||
{{% boxes/rationale %}}
|
||
虽然哈希不能百分百防止收集,但能显著增加批量收集标识的成本。手机号码通过哈希也难以完全隐匿,但这仍优于不加密。
|
||
|
||
另一种替代方案如 bcrypt 等多轮哈希算法,但考虑到需兼顾移动端与低性能设备,仍须保持加密过程较轻量。
|
||
{{% /boxes/rationale %}}
|
||
|
||
客户端应警惕服务器很久不轮换 pepper,或使用弱 pepper,这可能表明服务器试图暴力破解或利用彩虹表反查地址。同样,支持 `none` 算法的客户端,至少应向用户警示明文发送标识给身份服务器存在的风险。
|
||
|
||
某些标识(如手机号、电邮域名、已泄露地址)即使经哈希,仍可通过预计算的彩虹表逆推出原文。例如,手机号一般为 12 位左右,比邮箱更易被攻击。
|
||
|
||
## 建立关联
|
||
|
||
创建关联的流程基于 Session 会话。
|
||
|
||
在 Session 内,用户可证明其拥有某 3PID。一旦验证通过,用户即可将该 3PID 与 Matrix 用户 ID 关联。注意此流程的认证仅为单向,即用户可将任意已验证 3PID 关联到任意 Matrix 用户 ID,例如我可把自有邮箱地址与 @billg:microsoft.com 关联。
|
||
|
||
Session 有时效性:会话初建或发生验证时被认为已修改。只有在距离上次修改 24 小时内,Session 才可检查或执行验证。逾期后须新建 Session。
|
||
|
||
会话发起时,客户端请求对应 `/requestToken` 端点。身份服务器向用户发送验证 token,用户将该 token 提供给客户端,客户端再提交到 `/submitToken` 端点,整个会话结束。此时,客户端可选择 `/bind` 该 3PID,也可以留给其他实体进行绑定。
|
||
|
||
### 验证 token 格式
|
||
|
||
验证 token 的格式由身份服务器自行决定,应适合 3PID 类型(如不宜让用户从短信复制一长串带标点的口令)。
|
||
|
||
身份服务器采用何种格式皆可,但 token 必须不超过 255 个 Unicode 码点。客户端必须保持 token 不变地传递。
|
||
|
||
### 电子邮件关联
|
||
|
||
{{% http-api spec="identity" api="v2_email_associations" %}}
|
||
|
||
### 手机号关联
|
||
|
||
{{% http-api spec="identity" api="v2_phone_associations" %}}
|
||
|
||
### 通用
|
||
|
||
{{% http-api spec="identity" api="v2_associations" %}}
|
||
|
||
## 邀请存储
|
||
|
||
身份服务器可存储针对用户 3PID 的待处理邀请,这些邀请将在 3PID 绑定至 Matrix 用户 ID 后检索到,并可通知用户或供后续查询。
|
||
|
||
稍后,若 3PID 持有者将其绑定到 Matrix 用户 ID,身份服务器会尝试通过
|
||
[/3pid/onbind](/server-server-api#put_matrixfederationv13pidonbind)
|
||
端点向该 Matrix 用户的 homeserver 发送 HTTP POST 请求。请求必须由身份服务器某长期私钥签名。
|
||
|
||
{{% http-api spec="identity" api="v2_store_invite" %}}
|
||
|
||
## 临时邀请签名
|
||
|
||
为支持无法自行进行加密的客户端,身份服务器可提供部分加密能力,帮助其接受邀请。虽然这不如客户端自有加密安全,但在某些场景下仍有用。
|
||
|
||
{{% http-api spec="identity" api="v2_invitation_signing" %}}
|