当你作为开发人员保护 API 时,你将专注于授权。 若要调用资源的 API,应用程序需要 获取应用程序授权。 资源强制实施授权。 在本文中,你将了解实现 零信任 目标的最佳做法。 本文介绍如何通过注册、权限和许可定义以及访问强制实施来保护 API。
注册受保护的 API
若要 使用 Microsoft Entra ID(Microsoft Entra ID)保护 API , 请注册 API。 然后,可以 管理已注册的 API。 在Microsoft Entra ID 中,API 是一个具有特定应用注册设置的应用,可将它定义为另一个应用程序可以访问的资源或 API。 在 Microsoft Entra 管理中心,Microsoft Identity Developer 中的 应用注册 是位于租户中的 API,这些 API 可以是业务线 API,或是来自软件即服务 (SaaS) 提供商的服务,并由 Microsoft Entra ID 保护。
在注册期间,定义调用应用程序如何引用 API 及其 委派 权限和 应用程序权限。 应用注册可以表示同时具有客户端应用程序和 API 的解决方案。 但是,在本文中,我们解决了独立资源公开 API 的情况。
通常,API 不执行身份验证或直接请求授权。 API 验证调用应用显示的令牌。 API 没有交互式登录,因此无需注册重定向 URI 或应用程序类型等设置。 API 从调用这些 API 的应用程序获取令牌,而不是通过与 Microsoft Entra ID 进行交互。 对于 Web API,请使用 OAuth2 访问令牌 进行授权。 Web API 验证持有者令牌以授权调用方。 不接受 ID 令牌 作为权限证明。
默认情况下,Microsoft Entra ID 会将 User.Read 添加到任何新应用注册的 API 权限中。 对大多数Web API,您将取消此权限。 Microsoft Entra ID 仅当 API 调用另一个 API 时才需要 API 权限。 如果 API 不调用另一个 API,请在注册 API 时删除 User.Read 权限。
需要 API 的唯一标识符(称为 应用程序 ID URI),而需要访问 API 的客户端应用会请求调用 API 的权限。 应用程序 ID URI 在所有 Microsoft Entra 租户中都需要唯一。 可以在门户中使用 api://<clientId>(门户中的默认建议),其中 <clientId> 是已注册 API 的应用程序 ID。
若要为调用 API 的开发人员提供更易用的名称,可以使用 API 的地址作为应用程序 ID URI。 例如,在 Microsoft Entra 租户中,您可以在配置为发布者域的yourdomain.com使用https://API.yourdomain.com。 Microsoft验证你是否拥有域的所有权,以便将其用作 API 的唯一标识符。 您不需要在此地址存储代码。 API 可以放置在任何您希望的位置,但最好使用 https API 地址作为应用程序 ID URI。
使用最低权限定义委派权限
如果有用户的应用程序将调用您的 API,请定义至少一个 API 委托的权限范围(请参阅应用注册中的添加范围和公开 API)。
提供对组织数据存储的访问权限的 API 可以吸引想要访问这些数据的不良参与者的注意。 基于零信任原则设计权限,始终考虑到 最低特权访问,而不是仅依赖于一个委派权限。 如果所有客户端应用都以完全特权访问权限开始,则以后很难进入最低特权模型。
通常,开发人员会陷入一个模式,使用单个权限,例如以用户身份访问或用户冒充(这是一个技术上常见却不准确的短语)。 此类单个权限仅允许对 API 进行完全特权访问。
声明最低特权范围,使应用程序不会容易受到入侵或用于执行你从未期望的任务。 在 API 权限中定义多个范围。 例如,将范围与读取和更新数据分开,并考虑提供只读权限。 写入访问权限 包括创建、更新和删除操作的权限。 客户端永远不应要求对只读数据提供写入访问权限。
当 API 使用敏感数据时,请考虑 标准 访问权限和 完全 访问权限。 限制敏感属性,以便标准权限不允许访问(例如 Resource.Read)。 然后实现一个完全访问权限(例如 Resource.ReadFull),该权限返回属性和敏感信息。
始终评估请求的权限,以确保你寻求绝对最低特权集以完成作业。 避免请求更高的特权权限。 而是为每个核心方案创建单个权限。 有关此方法的良好示例,请参阅 Microsoft Graph 权限参考 。 找到并使用正确的权限数来满足你的需求。
定义用户同意和管理员同意
作为范围定义的一部分,确定是否可以使用特定范围执行的操作范围 需要管理员同意。
作为 API 设计器,可以提供有关哪些范围可以安全地要求用户同意的指导。 但是,租户管理员可以配置租户,以便所有权限都需要管理员同意。 如果将范围定义为需要管理员同意,权限始终需要管理员同意。
确定用户或管理员同意后,需要注意以下主要注意事项:
权限背后的操作范围是否影响多个用户。 如果权限允许用户选择哪个应用程序只能访问自己的信息,则用户同意可能合适。 例如,用户可以同意为电子邮件选择其首选应用程序。 但是,如果权限背后的操作涉及多个用户(例如查看其他用户的完整用户配置文件),则将该权限定义为需要管理员同意。
权限背后的操作范围是否具有广泛的范围。 例如,一个广泛的范围是,当某个权限使应用能够更改租户中的所有内容或执行可能不可逆的内容时。 广泛的范围表示需要管理员同意,而不是用户同意。
在不确定的情况下,倾向于保守,并需要管理员的许可。 简明清楚地描述许可字符串中同意的后果。 假设读取说明字符串的单个用户对 API 或产品不熟悉。
避免以更改权限语义的方式将 API 添加到现有权限。 重载现有权限会削弱客户端以前授予许可的推理。
定义应用程序权限
生成 非用户应用程序时,没有可以提示输入用户名和密码或多重身份验证(MFA)的用户。 如果没有用户(例如工作负载、服务和守护程序)的应用程序调用 API,请为 API 定义 应用程序权限 。 定义应用程序权限时,请使用 应用程序角色 而不是使用范围。
与委派权限一样,提供精细的应用程序权限,以便调用 API 的工作负载可以遵循最低特权访问,并符合零信任原则。 避免只发布一个应用角色(应用权限)和一个范围(委派权限),或向每个客户端公开所有操作。
工作负载使用客户端凭据进行身份验证,并请求一个带有.default 范围的令牌,如以下示例代码所示。
// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal or by PowerShell),
// and then granted by a tenant administrator
string[] scopes = new string[] { "https://kkaad.onmicrosoft.com/webapi/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
Console.WriteLine("Token acquired \n");
}
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
{
// Invalid scope. The scope has to be of the form "https://resourceurl/.default"
// Mitigation: change the scope to be as expected
Console.WriteLine("Scope provided is not supported");
}
当应用前没有用户且应用程序权限启用广泛的操作时,权限需要管理员同意。
强制实施访问权限
确保您的 API 通过验证和解释调用应用程序在请求的授权标头中提供的持有者令牌(Bearer tokens)来强制执行访问控制。 通过验证令牌、管理元数据刷新,以及应用作用域和角色来实施访问控制,如以下部分所述。
验证令牌
API 收到令牌后,请确保它 验证令牌。 验证可确保令牌来自正确的颁发者,且未篡改和未修改。 签名校验,因为你不像使用 ID 令牌那样直接从 Microsoft Entra ID 获取令牌。 在 API 从网络上不受信任的源接收令牌后验证签名。
由于 JSON Web 令牌签名验证存在已知漏洞,因此请使用维护完善的标准令牌验证库。 身份验证库(如 Microsoft.Identity.Web)使用适当的步骤并缓解已知漏洞。
(可选) 扩展令牌验证。 使用租户 ID (tid) 声明来限制 API 可以获取令牌的租户。 使用azp和appid声明来筛选可调用您 API 的应用。 使用对象 ID (oid)声明以进一步限定单个用户的访问权限。
管理元数据刷新
始终确保令牌验证库有效地管理所需的元数据。 在这种情况下,元数据是公钥和一对私钥,Microsoft 用于对 Microsoft Entra 令牌进行签名。 当库验证这些令牌时,它们将从知名的互联网地址获取已发布的公用签名密钥列表。 确保托管环境有适当的时机来获取这些密钥。
例如,旧库偶尔会硬编码,每 24 小时更新这些公钥签名密钥。 考虑何时Microsoft Entra ID 必须快速轮换这些密钥以及下载的密钥不包含新的轮换密钥。 API 可能在等待其元数据刷新周期时一天处于脱机状态。 参考 特定的元数据刷新指南 ,以确保正确获取元数据。 如果使用库,请确保它在合理的时间范围内处理该元数据。
强制实施范围和角色
验证令牌后,API 将查看令牌中的声明以确定其工作原理。
对于委派权限令牌,让 API 检查范围声明(scp)以确定应用程序被授权执行的操作。 检查对象 ID (oid) 或主体密钥 (sub) 的声明,以确定代表应用程序工作的用户。
然后进行 API 检查,确保用户也有权访问请求的操作。 如果 API 定义了分配给用户和组的角色,请让 API 检查令牌中的角色声明并相应地采取行动。 应用程序权限令牌没有范围(scp)声明。 相反,让 API 检查角色声明,以确定工作负荷收到的应用程序权限。
API 验证令牌和范围并处理对象 ID、oid主题密钥(sub和角色声明)后,API 可以返回结果。
后续步骤
- 受 Microsoft 标识同意框架保护的 API 示例可帮助你设计最低特权应用程序权限策略,以获得最佳用户体验。
- 从另一个 API 调用 API 可帮助你在一个 API 需要调用另一个 API 时确保零信任,并在应用程序代表用户工作时安全地开发应用程序。
- 自定义令牌介绍了可以在 Microsoft Entra 令牌中接收的信息。 本文介绍如何自定义令牌以提高灵活性和控制,同时提高应用程序零信任安全性(最低特权)。
- 在令牌中配置组声明和应用角色介绍了如何使用应用角色定义来配置应用,以及如何将安全组分配给应用角色。 这些方法有助于提高灵活性和控制,同时提高应用程序零信任安全性(最低特权)。
- 获取访问资源的授权 可帮助你了解如何在获取应用程序的资源访问权限时最好地确保零信任。
- 描述需要管理许可的请求权限 描述在应用程序权限需要管理许可时的权限和许可体验。
- 在本 快速入门中:使用Microsoft标识平台保护 Web API,了解如何通过将对 ASP.NET Web API 的访问权限限制为仅授权帐户来保护其资源。
- 在 本教程 - 在 Azure API 管理中转换和保护 API,了解如何配置通用策略以隐藏 API 的 HTTP 响应中的技术堆栈信息或原始 URL。