使用 Bot Connector API 进行身份验证

机器人使用通过安全通道 (SSL/TLS) 的 HTTP 与 Bot Connector 服务进行通信。 当机器人向 Connector 服务发送请求时,它必须包含 Connector 服务可以用来验证其身份的信息。 同样,当 Connector 服务向机器人发送请求时,它必须包含机器人可以用来验证其身份的信息。 本文介绍在机器人和 Bot Connector 服务之间进行的服务级身份验证的身份验证技术和要求。 如果正在编写自己的身份验证代码,必须实现本文所述的安全过程,以便机器人能够与 Bot Connector 服务交换消息。

重要

如果正在编写自己的身份验证代码,则必须正确实现所有安全程序。 通过实现本文中的所有步骤,可以降低攻击者能够读取发送到机器人的消息、发送模拟机器人的消息以及窃取密钥的风险。

如果使用的是 Bot Framework SDK,则不需要实现本文所述的安全程序,因为 SDK 会自动为你完成。 只需使用在注册期间为机器人获得的应用 ID 和密码配置项目,SDK 将处理其余部分。

身份验证技术

四个身份验证技术用于在机器人和 Bot Connector 之间建立信任:

技术 说明
SSL/TLS SSL/TLS 适用于所有服务到服务连接。 X.509v3 证书用于建立所有 HTTPS 服务的标识。 客户端应始终检查服务证书以确保它们受信任且有效。 (客户端证书不作为此方案的一部分使用。)
OAuth 2.0 OAuth 2.0 使用 Microsoft Entra ID 帐户登录服务,生成机器人可用于发送消息的安全令牌。 此令牌是服务到服务令牌;无需用户登录。
JSON Web 令牌 (JWT) JSON Web 令牌用于编码向机器人发送和从中发出的令牌。 客户端应根据本文中所述的要求完全验证他们收到的所有 JWT 令牌 。
OpenID 元数据 Bot Connector 服务发布一个有效令牌列表,用于在已知静态终结点上将自己的 JWT 令牌签署到 OpenID 元数据。

本文介绍如何通过标准 HTTPS 和 JSON 使用这些技术。 不需要特殊 SDK,尽管你可能发现 OpenID 之类的帮助程序很有用。

对从机器人到 Bot Connector 服务的请求进行身份验证

若要与 Bot Connector 服务通信,必须使用以下格式在每个 API 请求的 Authorization 标头中指定访问令牌:

Authorization: Bearer ACCESS_TOKEN

若要获取和使用机器人的 JWT 令牌:

  1. 机器人将 GET HTTP 请求发送到 MSA 登录服务。
  2. 来自服务的响应包含要使用的 JWT 令牌。
  3. 机器人在向 Bot Connector 服务发出的请求中的授权标头内包含此 JWT 令牌。

步骤 1:从 Microsoft Entra ID 帐户登录服务请求访问令牌

重要

如果尚未这样做,则必须向 Bot Framework 注册机器人以获取其应用 ID 和密码。 若要请求访问令牌,需要机器人的应用 ID 和密码。

可以通过几种不同的方式在 Azure 中管理机器人标识。

  • 作为用户分配的托管标识,因此无需自行管理机器人的凭据。
  • 作为单租户应用。
  • 作为多租户应用。

根据机器人的应用程序类型请求访问令牌。

若要从登录服务请求访问令牌,请发出以下请求,将 MICROSOFT-APP-IDMICROSOFT-APP-PASSWORD 替换为向机器人服务注册机器人时获得的机器人应用 ID 和密码。

POST https://login.partner.microsoftonline.cn/botframework.com/oauth2/v2.0/token
Host: login.partner.microsoftonline.cn
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=MICROSOFT-APP-ID&client_secret=MICROSOFT-APP-PASSWORD&scope=https%3A%2F%2Fapi.botframework.azure.cn%2F.default

步骤 2:从 Microsoft Entra ID 帐户登录服务响应获取 JWT 令牌

如果应用程序已由登录服务授权,那么 JSON 响应正文将指定访问令牌、其类型及其过期时间(以秒为单位)。

将令牌添加到请求的 Authorization 标头时,必须使用此响应中指定的确切值(即,不转义或编码令牌值)。 访问令牌有效,直到过期。 为了防止令牌过期影响机器人性能,可以选择缓存并主动刷新令牌。

此示例显示来自 Microsoft Entra ID 帐户登录服务的响应:

HTTP/1.1 200 OK
... (other headers)
{
    "token_type":"Bearer",
    "expires_in":3600,
    "ext_expires_in":3600,
    "access_token":"eyJhbGciOiJIUzI1Ni..."
}

步骤 3:指定请求的 Authorization 标头中的 JWT 令牌

当向 Bot Connector 服务发送 API 请求,使用此格式指定请求的 Authorization 标头中的访问令牌:

Authorization: Bearer ACCESS_TOKEN

发送到 Bot Connector 服务的所有请求都必须在 Authorization 标头中包含访问令牌。 如果令牌格式正确、未过期且其由 Microsoft Entra ID 帐户登录服务生成,则 Bot Connector 服务将对请求授权。 需执行额外检查以确保令牌属于发送请求的机器人。

下面的示例演示如何指定请求 Authorization 标头中的访问令牌。

POST https://smba.trafficmanager.net/teams/v3/conversations/12345/activities
Authorization: Bearer eyJhbGciOiJIUzI1Ni...

(JSON-serialized Activity message goes here)

重要

只在发送到 Bot Connector 服务的请求的 Authorization 标头中指定 JWT 令牌。 不要将令牌发送到非安全通道,也不要将其包含在发送给其他服务的 HTTP 请求中。 从 Microsoft Entra ID 帐户登录服务获取的 JWT 令牌类似于密码,应谨慎处理。 拥有令牌的任何人都可以使用它代表机器人执行操作。

机器人到 Connector:示例 JWT 组件

header:
{
  typ: "JWT",
  alg: "RS256",
  x5t: "<SIGNING KEY ID>",
  kid: "<SIGNING KEY ID>"
},
payload:
{
  aud: "https://api.botframework.azure.cn",
  iss: "https://sts.chinacloudapi.cn/d6d49420-f39b-4df7-a1dc-d59a935871db/",
  nbf: 1481049243,
  exp: 1481053143,
  appid: "<YOUR MICROSOFT APP ID>",
  ... other fields follow
}

注意

在实践中,实际字段可能会有所不同。 创建并验证上面指定的所有 JWT 令牌。

对从 Bot Connector 服务到机器人的请求进行身份验证

当 Bot Connector 服务将请求发送到机器人时,它会在请求的 Authorization 标头中指定已签名的 JWT 令牌。 通过验证已签名的 JWT 令牌的真实性,机器人可以对来自 Bot Connector 服务的调用进行身份验证。

若要对来自 Bot Connector 服务的调用进行身份验证:

  1. 机器人从自 Bot Connector 服务发出的请求中的授权标头内获取 JWT 令牌。
  2. 机器人获取 Bot Connector 服务的 OpenID 元数据文档。
  3. 机器人从文档获取有效的签名密钥列表。
  4. 机器人验证 JWT 令牌的真实性。

步骤 2:获取 OpenID 元数据文档

OpenID 元数据文档指定第二个文档的位置,其中列出了 Bot Connector 服务的有效签名密钥。 若要获取 OpenID 元数据文档,请通过 HTTPS 发出此请求:

GET https://login.botframework.azure.cn/v1/.well-known/openidconfiguration

提示

这是静态 URL,可以硬编码到应用程序。

下面的示例演示响应 GET 请求返回的 OpenID 元数据文档。 jwks_uri 属性指定包含 Bot Connector 服务的有效签名密钥的文档的位置。

{
    "issuer": "https://api.botframework.azure.cn",
    "authorization_endpoint": "https://invalid.botframework.azure.cn",
    "jwks_uri": "https://login.botframework.azure.cn/v1/.well-known/keys",
    "id_token_signing_alg_values_supported": [
      "RS256"
    ],
    "token_endpoint_auth_methods_supported": [
      "private_key_jwt"
    ]
}

步骤 3:获取有效签名密钥的列表

若要获取有效的签名密钥列表,请通过 HTTPS 向 OpenID 元数据文档中的 jwks_uri 属性指定的 URL 发出 GET 请求。 例如:

GET https://login.botframework.azure.cn/v1/.well-known/keys

响应正文指定 JWK 格式的文档,还包括每个密钥的其他属性:endorsements

提示

密钥列表是稳定的,可以缓存,但随时可能会有新密钥添加到其中。 为了确保在使用这些密钥之前机器人有文档的最新副本,所有机器人实例应至少每 24 小时刷新一次文档的本地缓存。

每个密钥中的 endorsements 属性包含一个或多个字符串,可用于验证在传入请求的 Activity 对象的 channelId 属性中定义的通道 ID 是否可信。 需要认可的通道 ID 列表在每个机器人中都可配置。 默认情况下,它将是所有已发布通道 ID 的列表,尽管机器人开发人员可能会通过任何一种方式重写选定通道的 ID 值。

步骤 4:验证 JWT 令牌

若要验证由 Bot Connector 服务发送的令牌的真实性,必须从请求的 Authorization 标头中提取令牌、分析令牌、验证其内容并验证其签名。

JWT 分析库适用于许多平台,并且大多数对 JWT 令牌实现安全且可靠的分析,尽管通常情况下必须配置这些库以请求令牌的某些特征(其颁发者、受众等)包含正确的值。 分析令牌时,必须配置分析库或编写你自己的验证来确保令牌满足这些要求:

  1. 令牌在 HTTP Authorization 标头中使用“持有者”方案发送。
  2. 令牌是有效的 JSON,符合 JWT 标准
  3. 令牌包含值为 https://api.botframework.azure.cn 的“颁发者”声明。
  4. 该令牌包含一个“受众”声明,其值等于机器人的 Microsoft 应用 ID。
  5. 该令牌在其有效期内。 行业标准时钟偏差为 5 分钟。
  6. 令牌具有有效的加密签名,包含在步骤 3 中检索到的 OpenID 密钥文档中列出的密钥,使用的是步骤 2 中检索到的 Open ID 元数据文档的 id_token_signing_alg_values_supported 属性中指定的签名算法。
  7. 该令牌包含“serviceUrl”声明,其值与传入请求的 Activity 对象根的 serviceUrl 属性匹配。

如果需要认可通道 ID:

  • 应请求使用通道 ID 发送到机器人的任何 Activity 对象随附 JWT 令牌,并签署有对该通道的认可。
  • 如果不存在认可,则机器人应通过返回“HTTP 403(禁止)”状态代码拒绝该请求。

重要

所有这些要求都很重要,尤其是要求 4 和 6。 如果未能实现所有这些验证要求将使机器人受到攻击,这可能会导致机器人公开其 JWT 令牌。

实施者不应公开禁用发送给机器人的 JWT 令牌的验证的方法。

Connector 到机器人:示例 JWT 组件

header:
{
  typ: "JWT",
  alg: "RS256",
  x5t: "<SIGNING KEY ID>",
  kid: "<SIGNING KEY ID>"
},
payload:
{
  aud: "<YOU MICROSOFT APP ID>",
  iss: "https://api.botframework.azure.cn",
  nbf: 1481049243,
  exp: 1481053143,
  ... other fields follow
}

注意

在实践中,实际字段可能会有所不同。 创建并验证上面指定的所有 JWT 令牌。

对从 Bot Framework Emulator 到机器人的请求进行身份验证

Bot Framework Emulator 是一个桌面工具,可用于测试机器人的功能。 虽然 Bot Framework Emulator 使用如上所述的相同身份验证技术,但它无法模拟真实的 Bot Connector 服务。 与之相反,它使用在将 Emulator 连接到机器人时所指定的 Microsoft 应用 ID 和 Microsoft 应用密码,以创建与机器人创建的令牌相同的令牌。 在 Emulator 向机器人发送请求时,它将在请求的 Authorization 标头中指定 JWT 令牌,从本质上讲,这是使用机器人自己的凭据对请求进行身份验证。

如果要实现身份验证库,并想要接受来自 Bot Framework Emulator 的请求,则必须添加此附加验证路径。 此路径在结构上类似于 Connector -> Bot 验证路径,但它使用 MSA 的 OpenID 文档而不是 Bot Connector 的 OpenID 文档。

如要对从 Bot Framework Emulator 的调用进行身份验证:

  1. 机器人从自 Bot Framework Emulator 发出的请求中的授权标头内获取 JWT 令牌。
  2. 机器人获取 Bot Connector 服务的 OpenID 元数据文档。
  3. 机器人从文档获取有效的签名密钥列表。
  4. 机器人验证 JWT 令牌的真实性。

步骤 2:获取 MSA OpenID 元数据文档

OpenID 元数据文档指定第二个文档的位置,其中列出了有效签名密钥。 若要获取 MSA OpenID 元数据文档,请通过 HTTPS 发出此请求:

GET https://login.partner.microsoftonline.cn/botframework.com/v2.0/.well-known/openid-configuration

下面的示例演示响应 GET 请求返回的 OpenID 元数据文档。 jwks_uri 属性指定文档的位置,其中包含有效的签名密钥。

{
    "authorization_endpoint":"https://login.partner.microsoftonline.cn/common/oauth2/v2.0/authorize",
    "token_endpoint":"https://login.partner.microsoftonline.cn/common/oauth2/v2.0/token",
    "token_endpoint_auth_methods_supported":["client_secret_post","private_key_jwt"],
    "jwks_uri":"https://login.partner.microsoftonline.cn/common/discovery/v2.0/keys",
    ...
}

步骤 3:获取有效签名密钥的列表

若要获取有效的签名密钥列表,请通过 HTTPS 向 OpenID 元数据文档中的 jwks_uri 属性指定的 URL 发出 GET 请求。 例如:

GET https://login.partner.microsoftonline.cn/common/discovery/v2.0/keys
Host: login.partner.microsoftonline.cn

响应正文指定 JWK 格式的文档。

步骤 4:验证 JWT 令牌

若要验证 Emulator 发送的令牌的真实性,必须从请求的 Authorization 标头提取令牌,分析令牌,验证其内容,然后验证其签名。

JWT 分析库适用于许多平台,并且大多数对 JWT 令牌实现安全且可靠的分析,尽管通常情况下必须配置这些库以请求令牌的某些特征(其颁发者、受众等)包含正确的值。 分析令牌时,必须配置分析库或编写你自己的验证来确保令牌满足这些要求:

  1. 令牌在 HTTP Authorization 标头中使用“持有者”方案发送。
  2. 令牌是有效的 JSON,符合 JWT 标准
  3. 令牌包含一个“颁发者”声明,其中包含非政府案例的突出显示值之一。 检查两个颁发者值将确保检查安全协议 v3.1 和 v3.2 颁发者值。
  4. 该令牌包含一个“受众”声明,其值等于机器人的 Microsoft 应用 ID。
  5. Emulator 会根据版本通过 appid 声明(版本 1)或授权方声明(版本 2)发送 AppId。
  6. 该令牌在其有效期内。 行业标准时钟偏差为 5 分钟。
  7. 令牌具有有效的加密签名,包含在步骤 3 中检索到的 OpenID 密钥文档中列出的密钥。

注意

要求 5 特定于 Emulator 验证路径。

如果令牌不满足所有这些要求,则机器人应通过返回“HTTP 403(禁止)”状态代码终止该请求。

重要

所有这些要求都很重要,尤其是要求 4 和 7。 如果未能实现所有这些验证要求将使机器人受到攻击,这可能会导致机器人公开其 JWT 令牌。

Emulator 到机器人:示例 JWT 组件

header:
{
  typ: "JWT",
  alg: "RS256",
  x5t: "<SIGNING KEY ID>",
  kid: "<SIGNING KEY ID>"
},
payload:
{
  aud: "<YOUR MICROSOFT APP ID>",
  iss: "https://sts.chinacloudapi.cn/d6d49420-f39b-4df7-a1dc-d59a935871db/",
  nbf: 1481049243,
  exp: 1481053143,
  ... other fields follow
}

注意

在实践中,实际字段可能会有所不同。 创建并验证上面指定的所有 JWT 令牌。

安全协议更改

机器人到 Connector 身份验证

OAuth 登录 URL

协议版本 有效值
v3.1 和 v3.2 https://login.partner.microsoftonline.cn/botframework.com/oauth2/v2.0/token

OAuth 作用域

协议版本 有效值
v3.1 和 v3.2 https://api.botframework.azure.cn/.default

Connector 到机器人身份验证

OpenID 元数据文档

协议版本 有效值
v3.1 和 v3.2 https://login.botframework.azure.cn/v1/.well-known/openidconfiguration

JWT 颁发者

协议版本 有效值
v3.1 和 v3.2 https://api.botframework.azure.cn

Emulator 到机器人身份验证

OAuth 登录 URL

协议版本 有效值
v3.1 和 v3.2 https://login.partner.microsoftonline.cn/botframework.com/oauth2/v2.0/token

OAuth 作用域

协议版本 有效值
v3.1 和 v3.2 机器人的 Microsoft 应用 ID + /.default

JWT 受众

协议版本 有效值
v3.1 和 v3.2 机器人的 Microsoft 应用 ID

JWT 颁发者

协议版本 有效值
v3.1 1.0 https://sts.chinacloudapi.cn/d6d49420-f39b-4df7-a1dc-d59a935871db/
v3.1 2.0 https://login.partner.microsoftonline.cn/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0
v3.2 1.0 https://sts.chinacloudapi.cn/f8cdef31-a31e-4b4a-93e4-5f571e91255a/
v3.2 2.0 https://login.partner.microsoftonline.cn/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0

另请参阅非政府案例的突出显示值之一。

OpenID 元数据文档

协议版本 有效值
v3.1 和 v3.2 https://login.partner.microsoftonline.cn/botframework.com/v2.0/.well-known/openid-configuration

其他资源