描述 API 安全性

OpenAPI 的一项功能可以证明对 API 提供者和消费者有用,即描述 API 安全性的方法。提供有关保护给定 API 及其操作的安全性的信息对人类很有用,因为他们可以理解安全限制并在其实现中考虑这些限制,并且对于可以生成代码或提供功能以促进提交授权参数的工具而言也很有用。

OpenAPI 提供了 安全方案对象,其中包含可以全局引用或按 操作 引用的安全定义。与其他组件对象不同,安全方案对象通过使用 安全需求对象 按名称引用。因此,给定 API 或操作的安全描述必须定义为安全方案对象,因为它们不能内联声明。

安全方案对象作为安全需求被引用,无论是 全局 还是由 操作 引用。

为给定操作声明的安全需求优先于全局安全需求。支持多种安全机制。每种机制都使用 type 属性指示,如以下示例所示。

目前支持五种安全类型,即

  • API 密钥
  • HTTP 身份验证
  • 双向 TLS
  • OAuth 2.0
  • OpenID Connect

下面各节将讨论每个类型。

API 密钥

API 密钥一般来说是 API 等效的密码,用于提供只有给定 API 消费者和 API 提供者知道的密钥。没有管理 API 密钥的正式标准,行业通常依赖于公认的最佳实践来定义它们。因此,OpenAPI 在定义 API 密钥时提供了灵活性。

例如,API 提供者可能会使用 HTTP 标头 api-key 作为 API 消费者在每个请求中发送 API 密钥的方法。可以定义一个安全方案对象,以指示应在哪个 HTTP 标头中发送 API 密钥。

components:
  securitySchemes:
    defaultApiKey:
      description: API key provided in console
      type: apiKey
      name: api-key
      in: header

然后,API 提供者可以使用此方案方案对象的名称全局应用安全性,或为给定操作应用安全性(以下两者都为了举例而显示)

openapi: 3.1.0
info:
  title: Tic Tac Toe
  description: |
    This API allows writing down marks on a Tic Tac Toe board
    and requesting the state of the board or of individual squares.
  version: 1.0.0
security:
  defaultApiKey: []
paths:
  /board:
    get:
      security:
        defaultApiKey: []

这种引用安全方案对象的方法对所有类型都有效。上面显示的作为 defaultApiKey 值的数组是针对 OAuth Flow 和 OpenID Connect 对象填充的,它们具有一些额外的功能,将在下面讨论。在所有其他情况下,将提供一个空数组。

请注意,不同的工具可能会以不同的方式解析引用文档中的安全需求对象。您应该在假设特定解析方法之前检查您的工具提供商的方法。

HTTP 身份验证

OpenAPI 支持 RFC7235 中定义的 HTTP 身份验证,该标准实现了 Authorization 标头作为发送授权方案标识符和参数的方式,格式为 Authorization: Basic b3BlbmFwaTppc2dyZWF0。授权方案应该IANA HTTP 身份验证注册表 中定义,但 API 提供者可以在需要时扩展此方案以使用自定义值。

以下示例显示了一个安全方案对象,该对象指定了基本身份验证和承载令牌。承载令牌示例包含一个额外的提示,即 bearerFormat 属性,该属性向 API 消费者提供了有关令牌格式的额外信息(在本例中为 JSON Web 令牌 或 JWT)。

components:
  securitySchemes:
    basicHttpAuthentication:
      description: Basic HTTP Authentication
      type: http
      scheme: Basic
    bearerHttpAuthentication:
      description: Bearer token using a JWT
      type: http
      scheme: Bearer
      bearerFormat: JWT

您会注意到,在这两种情况下,提供的信息都比较简短。OpenAPI 提供了足够的信息,使人类和工具能够理解基本的安全需求,但部署信息(如入职或密钥交换)不在范围内。

双向 TLS

通过 TLS (mTLS) 的双向身份验证是金融服务等垂直行业中非常常见的 API 安全方法。这是因为它通过在传输层对 HTTP 客户端进行身份验证来增强安全态势。

在 OpenAPI 中定义 mTLS 非常简单

type: mutualTLS

与之前一样,提供的信息很简短。建立用于管理 API 提供者和消费者之间通信的私钥基础设施,以及相关的部署信息(如证书签名等)超出了 OpenAPI 的范围。

OAuth 2.0

OAuth 2.0 是一种非常流行的 API 世界中的授权框架,因为它支持委托访问,而无需将最终用户的凭据泄露给不受信任的应用程序。它使用一个特定的对象来描述,即 OAuth Flows 对象。提供此对象是因为与其他安全类型相比,该协议的复杂性相对较高,不同的授权类型代表了获取访问受保护资源授权的不同机制。

OAuth Flows 对象具有代表不同 OAuth 2.0 授权类型的属性,每个属性都引用 OAuth Flow 对象。OAuth Flow 对象属性描述授权服务器 URL、令牌端点,并可选地描述允许的 OAuth 范围。

以下示例显示了客户端凭据和授权代码授权类型的属性

components:
  securitySchemes:
    oauth2Profiles:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://learn.openapis.org.cn/oauth/2.0/token
          scopes:
            board:read: Read the board
            board:write: Write to the board
        authorizationCode:
          authorizationUrl: https://learn.openapis.org.cn/oauth/2.0/auth
          tokenUrl: https://learn.openapis.org.cn/oauth/2.0/token
          scopes:
            board:read: Read the board
            board:write: Write to the board

然后可以全局应用这些属性,或者为给定操作应用这些属性,并附带所需范围的列表

openapi: 3.1.0
info:
  title: Tic Tac Toe
  description: |
    This API allows writing down marks on a Tic Tac Toe board
    and requesting the state of the board or of individual squares.
  version: 1.0.0
security:
  oauth2Profiles:
    - board:read
    - board:write
paths:
  /board:
    get:
      security:
        oauth2Profiles: []

请注意,如果您想隔离授权类型(例如,客户端凭据仅在特定操作中支持),则需要创建一个单独的安全方案对象,该对象可以单独应用。如果您想区分可用的范围,情况也是如此,例如

components:
  securitySchemes:
    app2AppOauth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://learn.openapis.org.cn/oauth/2.0/token
            # Only reading the board allow with delegated access
            board:read: Read the board
    user2AppOauth:
        authorizationCode:
          authorizationUrl: https://learn.openapis.org.cn/oauth/2.0/auth
          tokenUrl: https://learn.openapis.org.cn/oauth/2.0/token
          scopes:
            # Reads and writes permitted via authorization code flow
            board:read: Read the board
            board:write: Write to the board

然后将这些范围声明为单独的安全需求

info:
  title: Tic Tac Toe
  description: |
    This API allows writing down marks on a Tic Tac Toe board
    and requesting the state of the board or of individual squares.
  version: 1.0.0

paths:
  /board:
    get:
      security:
        app2AppOauth:
        - board:read
      ...
  /board/{row}/{column}:
    put:
      security:
        user2AppOauth:
        - board:read
        - board:write
      ...

请参阅我们的 示例 OpenAPI 文档,了解完整的示例。

OpenID Connect

最后一个安全方案类型是 OpenID Connect,它提供 OpenID Connect 发现 的信息。

OpenID Connect Core 显然是 OAuth 2.0 配置文件,并且受 OAuth Flow 对象的某些属性支持。但是,OpenID Connect 通常比普通 OAuth 2.0 更复杂,并且鉴于 OpenID Connect 发现提供了发现端点的机器可读格式,因此有必要将此功能完全外包。

因此,指定 OpenID Connect 很简单,您只需要在 openIdConnectUrl 属性中提供发现端点即可

components:
  securitySchemes:
    openIdConnect:
      type: openIdConnect
      openIdConnectUrl: https://learn.openapis.org.cn/.well-known/openid-configuration

这里巧妙之处在于,您不需要在 OpenAPI 文档中声明范围。您可以在发现端点中指定范围,然后在 OpenAPI 文档中使用它们,并期望兼容的工具已解析并读取它们

openapi: 3.1.0
info:
  title: Tic Tac Toe
  description: |
    This API allows writing down marks on a Tic Tac Toe board
    and requesting the state of the board or of individual squares.
  version: 1.0.0
security:
  openIdConnect:
    - board:read
    - board:write

这种方法允许 OpenAPI 为人类和工具提供足够的信息,同时确保 OpenID Connect 发现提供了安全相关信息的系统记录。

总结

在本页中,我们了解到

  • API 安全性可以在 OpenAPI 中描述。
  • 安全属性必须使用安全方案对象来描述。
  • 安全方案对象通过使用安全需求全局引用或为给定操作引用。
  • OpenAPI 支持多种内置安全类型,不同类型具有不同的属性。