近期在公司推广实施安全开发生命周期流程(SDL), 基于目前业务的发展, 有很多以 API 形式提供的数据访问接口, 为此专门对所有系统的 API 接口进行了一次梳理, 在梳理过程中发现了部分接口存在的安全隐患, 包括未授权访问, 数据校验不完整, 访问敏感数据等问题. 因此在这里针对 API 可能带来的安全问题听过一些安全解决措施, 大家一起交流学习.
随着业务开放性的发展趋势, 为了应对快速发展的业务及灵活多变的程序需求, API(Application Programming Interface)在程序中的应用显得愈发重要, API 为外部业务对接, 系统间的调用提供了灵活性和创新性. 然而与此同时, 随之而来的则是 API 应用带来的一系列安全问题, 任意访问, 数据泄露, 窃取用户信息等, API 的使用不当都可能破坏数据的保密性, 完整性和可用性.
一个安全的 API 仅可对其用户, 应用程序, 以及消费它的服务可见, 以此确保信息的保密性; 除此之外, 同时要保证客户端和服务端间交互的信息没有被第三方篡改, 以此保证信息的完整性. 要满足信息的保密性和完整性, 对调用方和终端用户进行身份认证是前提条件.
身份验证可以说是安全界的核心. API 创建者需要有能力识别消费 API 的用户, 应用以及调用 API 的服务, 那么就需要有一个身份存储库来识别并确认用户和应用的身份有效性. 身份存储库目前最常用的解决方案就是 LDAP 服务, 而活动目录 (AD) 是目前对 LDAP 最流行的一种实现. LDAP 服务主要存储用户名, 密码, 数字证书以及其他用户相关的身份信息和用户所属机构组织信息, 应用的身份信息同样可以存储在这里. 身份提供者 (IP) 是专用于管理与身份存储库的交互以用于身份验证和授权的软件, App 可以将身份验证及授权的工作交由身份提供者处理, 这是一种更加安全和可取的方法.
当调用者使用应用 ID 和用户名调用你的 API 时, API 需要有能力识别调用者提供的信息的有效性, 这种有效性验证主要是通过验证共享的秘密信息来完成的. 当你的 API 作为身份提供者时, 通常会传递同样的身份认证信息到 LDAP 服务进行验证. 下面介绍几种常用的 API 身份验证的方法.
第一种就是用户名密码方式, 这也是最简单的一种认证方式. 系统间身份认证使用这种方式实现时, 身份认证使用的密码可能会在多个 API 间进行共享. 用户名密码身份认证方式并不推荐使用, 主要是基于两方面的考虑: 首先是由于密码的可猜测性, 密码是人为生成, 安全性较低; 其次是密码的维护工作也存在困难, 例如修改某个 API 进行身份认证的密码, 那么所有相关联的应用都会受到影响.
第二种是多因素认证方式(MFA), 即在用户知道什么的前提下, 进一步通过用户有什么进行身份验证, 通过用户获取到的一次性 token 来进一步验证用户身份凭证. 这个 token 可以是 MFA 服务提供者发送的短信, 也可以是数字 key, 目前已经有成熟的第三方数字 key 服务提供商, 开源的有 Google Authenticator,FreeOTP, 商用的则有 RSASecurID.
第三种方式是基于 Token 的身份认证凭证, 是对用户名密码安全性的补充, 为用户名密码的认证和授权提供了一种更加安全的方式. 身份提供者基于用户名密码的身份凭证生成一个独立的 token, 后续与应用的交互, 只需要将该 token 传递给应用, 因此通过网络来回切换的用户名 / 密码凭证大幅减少. 同时, token 被设置了过期时间并且可以被撤销, 从而保证了 token 使用上的安全性. 更重要的是, 针对每个应用都生成对应的独立 token, 当撤销或者失效某一个 token 时, 其他应用仍可以正常使用自己的 token, 无需再次进行用户名密码认证.
如下图所示, 用户 Gary 登录应用, 应用验证其用户名密码身份信息, 并向身份提供者申请 token, 身份提供者在身份存储库中验证 Gary 的身份有效性, 验证通过后, 身份提供者向应用返回 token, 接下来应用就可以使用这个 token 作为调用 API 的身份凭证. 这也是目前网络认证协议 Kerberos 的实现基本原理.
接下来要介绍的是联合身份认证机制. 基于令牌的身份认证方式允许将令牌的发布与其验证分开, 从而促进身份管理的集中化. API 的开发者只需要关心用户在调用 API 时的验证逻辑, 不需要关心具体的身份认证逻辑, 这部分是由集中式身份提供者完成的, API 只需要在请求中带上 token, 然后由集中式身份提供者完成对 token 有效性的验证, 如果生成的 token 有权限发起这次请求, 则 API 将被允许调用. 身份提供者能够对用户, 应用及 App 的身份进行识别和认证, 是基于它们的身份信息和共享密码都存储在身份存储库中. 但是, 你的 API 不会始终暴露给身份提供者能识别的应用和用户, 如果你希望将你的 API 暴露给外部用户控制的应用, 外部用户可能来自于其他公司或者公司内部的其他业务部门, 这时候该如何控制 API 的安全性呢? 尤其是对于大公司而言, 他们有很多的安全上下文, 每个安全上下文都包含有独立的身份存储库和身份提供者, 此时, 联合身份机制应运而生, 联合身份提供者能够对来自不同安全上下文的用户进行认证和授权.
联合身份认证机制的流程如下图所示, 与普通的基于 token 的身份认证流程类似, 但流程中增加了物流 API 和物流系统身份提供者两个角色, 应用利用订单系统身份提供者返回的有效 token 申请访问物流 API, 物流 API 向物流系统身份提供者申请验证 token 有效性, 但它并不知道此 token 是否有效, 必须向订单系统身份提供者申请验证此 token, 而不是在物流身份存储库中检索此 token 的信息, 这里的订单系统身份提供者和物流系统身份提供者就是联合身份提供者.
身份认证完成之后, 就需要根据用户的身份对其进行授权, 其权限的大小由其身份决定. 下面就介绍几种在 API 安全中使用的授权模式.
第一种是最常用的基于角色的访问控制模型. 每个企业或组织的员工都会根据其业务职责划分成不同的部门或组. 那么这些组织内的员工就根据其分组界定其权限. 分组信息就可以应用在于应用交互中, 根据应用的授权及在应用中设置不同分组的访问规则来限制用户的访问, 用户所在分组决定其在应用中的角色权限. 轻量级目录访问协议 (LDAP) 服务正是利用了分组的概念. 身份提供者负责从身份存储库中检索分组信息, 角色则是应用对访问控制权限的具体定义, 用户则可以采用应用定义的多个角色.
基于角色的访问控制是一种非常简单的访问控制机制. 应用不需要维护每个用户能访问的数据和功能, 只需要通过角色将数据和功能访问权限抽象化, 而只需要根据用户的角色分配不同的访问权限.
第二种授权方式是基于属性的访问控制模型 (ABAC). 不同于基于静态角色访问控制方式, 基于属性的访问控制旨在调用 API 时根据用户的环境信息动态分配其访问控制权限, 环境信息包括如访问时间, 角色, API 的地理位置, 应用的地理位置以及其他决定访问程度的条件的组合信息. 可扩展的访问控制标识语言(XACML) 是一种基于 xml 的开放标准语言, 是一种用于决定请求 / 响应的通用访问控制策略语言和执行授权策略的框架, 可定义 API 调用时访问控制规则, 这种规则可以在不同 API 调用时进行动态变换, 是一种典型的 ABAC 环境下的策略描述语言.
第三种是基于 OAuth 2.0 的代理访问控制方式. 基于 HTTP 的 OAuth 2.0 框架允许应用程序代表自己或代表用户获取对 API 资源的访问权限. 因此, 它允许用户将访问控制委派给第三方应用程序. 为此, 你的 API 接口必须与 OAuth 2.0 授权服务器协作, 检查每次请求访问 token 时, 都经过授权服务器的校验. 授权服务器则向请求方返回响应, 指明访问 token 是否有效, 是否是由 OAuth 提供者生成并且未过期的, 同时校验该 token 能访问的范围.
提到联合身份认证机制, 就不得不提到安全断言标记语言 (SAML). 安全断言标记语言(SAML) 是一种行业标准, 已成为企业级身份联合的事实标准. 它允许身份提供者以标准方式将有关用户的身份验证和授权信息传递给服务提供者. SAML 断言可以由一个安全上下文中的身份提供者发布, 并被另一个安全上下文中的身份提供者所理解. SAML 断言通常传达有关用户的信息给另一个身份提供者, 包括用户所属组织, 以及断言的到期时间, 无需提供密码信息, 验证断言有效性的身份提供者必须与发布断言的身份提供者建立信任关系. 在企业内使用 SAML 的主要场景就是单点登录(SSO), 用户无需为每个需要登陆的应用单独维护一套身份信息, 仅仅需要在服务提供者处注册登陆一次即可畅通无阻的访问其他应用.
这里介绍一种实现 SSO 身份认证常用的协议 - OpenID Connect.OpenID Connect 构建于 OAuth 2.0 之上, 提供联合身份机制来保护你的 API. 它不但能支持原生和移动应用程序, 同样适用于企业级应用, 它基于 JSON/REST 的协议使其应用更加简便快捷, 是一种在企业内部实现单点登录更加轻量级的解决方案. 不同于 OAuth 2.0 的访问 token,OpenIDConnect 使用 JWT ID token,token 中包含已经身份验证通过的用户的标准格式信息. API 可以通过调用身份提供者上的用户信息端点来确定访问控制策略, 以验证用户是否属于某个角色. 与 SAML 断言一样, JWT ID 令牌经过数字签名, 因此联合身份提供者可以根据与发布它们的身份提供者的信任关系来决定是否接受此 token.
认证和授权是 API 安全的前提, 一个安全的 API 应该有能力识别调用它的系统和终端用户的身份, 本文介绍了几种认证和授权机制, 来加强 API 的安全性, 在实际应用场景中, 可以根据具体情况采用不同的实现方式, 也希望大家能够更多交流 API 安全这方面的经验和问题.
来源: http://www.tuicool.com/articles/3YnUBz7