跳到主要内容

10. Security Considerations

  1. 安全考虑

作为一个灵活且可扩展的框架, OAuth 的安全考虑取决于许多因素. 以下各节为实现者提供安全指南, 重点关注第 2.1 节描述的三种客户端配置文件: Web 应用程序, 基于用户代理的应用程序和原生应用程序.

[OAuth-THREATMODEL] 提供了完整的 OAuth 安全模型和分析, 以及协议设计背景.

10.1. 客户端认证

授权服务器为 Web 应用程序客户端建立客户端凭据, 以用于客户端认证. 鼓励授权服务器考虑比客户端密码更强的客户端认证方式. Web 应用程序客户端必须确保客户端密码和其他客户端凭据的机密性.

授权服务器禁止为了客户端认证目的向原生应用程序或基于用户代理的应用程序客户端签发客户端密码或其他客户端凭据. 授权服务器可以为特定设备上某个原生应用程序客户端的特定安装签发客户端密码或其他凭据.

当无法进行客户端认证时, 授权服务器应当采用其他方式验证客户端身份, 例如要求注册客户端重定向 URI, 或让资源所有者参与确认身份. 在请求资源所有者授权时, 有效的重定向 URI 不足以验证客户端身份, 但在获得资源所有者授权后, 可用于防止将凭据交付给伪造客户端.

授权服务器必须考虑与未认证客户端交互的安全影响, 并采取措施限制签发给这类客户端的其他凭据 (例如刷新令牌) 的潜在暴露.

10.2. 客户端冒充

如果被冒充的客户端未能或无法保密其客户端凭据, 恶意客户端就可以冒充另一个客户端并获得对受保护资源的访问权限.

授权服务器必须在可行时认证客户端. 如果由于客户端性质而无法认证客户端, 授权服务器必须要求注册任何用于接收授权响应的重定向 URI, 并且应当利用其他方式保护资源所有者免受这类潜在恶意客户端影响. 例如, 授权服务器可以让资源所有者参与识别客户端及其来源.

授权服务器应当强制执行明确的资源所有者认证, 并向资源所有者提供有关客户端以及所请求授权作用域和生命周期的信息. 资源所有者负责在当前客户端的上下文中审查这些信息, 并授权或拒绝请求.

在未认证客户端或未依赖其他措施确保重复请求来自原始客户端而非冒充者的情况下, 授权服务器不应自动处理重复的授权请求 (即没有资源所有者主动交互).

10.3. 访问令牌

访问令牌凭据 (以及任何机密访问令牌属性) 在传输和存储时必须保持机密, 并且只能在授权服务器, 访问令牌适用的资源服务器以及访问令牌签发目标客户端之间共享. 访问令牌凭据只能使用第 1.6 节所述的 TLS 传输, 并按 [RFC2818] 定义进行服务器认证.

使用隐式许可类型时, 访问令牌在 URI 片段中传输, 这可能使其暴露给未授权方.

授权服务器必须确保未授权方无法生成, 修改或猜测出有效的访问令牌.

客户端应当请求具有所需最小作用域的访问令牌. 授权服务器在决定如何满足请求的作用域时应当考虑客户端身份, 并且可以签发权限少于请求权限的访问令牌.

本规范未提供任何方法让资源服务器确认某个客户端提交给它的访问令牌是否由授权服务器签发给该客户端.

10.4. 刷新令牌

授权服务器可以向 Web 应用程序客户端和原生应用程序客户端签发刷新令牌.

刷新令牌在传输和存储时必须保持机密, 并且只能在授权服务器和刷新令牌签发目标客户端之间共享. 授权服务器必须维护刷新令牌与其签发目标客户端之间的绑定. 刷新令牌只能使用第 1.6 节所述的 TLS 传输, 并按 [RFC2818] 定义进行服务器认证.

每当能够认证客户端身份时, 授权服务器必须验证刷新令牌与客户端身份之间的绑定. 当无法进行客户端认证时, 授权服务器应当部署其他方式检测刷新令牌滥用.

例如, 授权服务器可以采用刷新令牌轮换, 即在每次访问令牌刷新响应中签发一个新的刷新令牌. 先前的刷新令牌会失效, 但由授权服务器保留. 如果刷新令牌被攻破并随后被攻击者和合法客户端同时使用, 其中一方将提交已失效的刷新令牌, 这会告知授权服务器发生了泄露.

授权服务器必须确保未授权方无法生成, 修改或猜测出有效的刷新令牌.

10.5. 授权码

授权码应当通过安全信道传输, 并且如果客户端的重定向 URI 标识网络资源, 客户端应当要求其重定向 URI 使用 TLS. 由于授权码通过用户代理重定向传输, 它们可能通过用户代理历史记录和 HTTP Referer 头泄露.

授权码作为明文持有者凭据运行, 用于验证在授权服务器授予授权的资源所有者, 与返回客户端完成流程的资源所有者是同一个人. 因此, 如果客户端依赖授权码来进行自身的资源所有者认证, 客户端重定向端点必须要求使用 TLS.

授权码必须短生命周期且只能使用一次. 如果授权服务器观察到多次尝试用同一授权码交换访问令牌, 授权服务器应当尝试撤销所有已基于该被攻破授权码授予的访问令牌.

如果客户端可以被认证, 授权服务器必须认证客户端, 并确保授权码签发给同一客户端.

10.6. 授权码重定向 URI 操纵

使用授权码许可类型请求授权时, 客户端可以通过 "redirect_uri" 参数指定重定向 URI. 如果攻击者能够操纵重定向 URI 的值, 就可能导致授权服务器将资源所有者的用户代理连同授权码一起重定向到攻击者控制的 URI.

攻击者可以在合法客户端上创建账户并启动授权流程. 当攻击者的用户代理被发送到授权服务器以授予访问时, 攻击者取得合法客户端提供的授权 URI, 并将客户端的重定向 URI 替换为攻击者控制的 URI. 然后, 攻击者诱骗受害者跟随被操纵的链接, 授权合法客户端访问.

到达授权服务器后, 受害者会看到代表合法且受信任客户端发起的正常有效请求, 并授权该请求. 随后受害者被重定向到攻击者控制的端点并携带授权码. 攻击者通过使用客户端最初提供的原始重定向 URI 将授权码发送给客户端, 从而完成授权流程. 客户端用授权码交换访问令牌, 并将其关联到攻击者的客户端账户, 该账户现在可以访问受害者授权的受保护资源 (通过客户端).

为防止此类攻击, 授权服务器必须确保用于获得授权码的重定向 URI 与用授权码交换访问令牌时提供的重定向 URI 完全相同. 授权服务器必须要求公共客户端注册其重定向 URI, 并且应当要求机密客户端注册其重定向 URI. 如果请求中提供了重定向 URI, 授权服务器必须依据已注册值对其进行验证.

10.7. 资源所有者密码凭据

资源所有者密码凭据许可类型通常出于遗留或迁移原因使用. 它降低了客户端保存用户名和密码的总体风险, 但并未消除向客户端暴露高权限凭据的需要.

这种许可类型的风险高于其他许可类型, 因为它保留了本协议试图避免的密码反模式. 客户端可能滥用密码, 或者密码可能无意中暴露给攻击者 (例如通过日志文件或客户端保存的其他记录).

此外, 由于资源所有者无法控制授权过程 (资源所有者的参与在其将凭据交给客户端时结束), 客户端可能获得比资源所有者期望更宽作用域的访问令牌. 授权服务器应当考虑通过此许可类型签发的访问令牌的作用域和生命周期.

授权服务器和客户端应当尽量减少使用这种许可类型, 并在可能时使用其他许可类型.

10.8. 请求机密性

访问令牌, 刷新令牌, 资源所有者密码和客户端凭据禁止以明文传输. 授权码不应以明文传输.

"state" 和 "scope" 参数不应以明文包含敏感的客户端或资源所有者信息, 因为它们可能通过不安全信道传输或以不安全方式存储.

10.9. 确保端点真实性

为防止中间人攻击, 对于发送到授权端点和令牌端点的任何请求, 授权服务器必须要求使用按 [RFC2818] 定义进行服务器认证的 TLS. 客户端必须按 [RFC6125] 定义并根据其服务器身份认证要求验证授权服务器的 TLS 证书.

10.10. 凭据猜测攻击

授权服务器必须防止攻击者猜测访问令牌, 授权码, 刷新令牌, 资源所有者密码和客户端凭据.

攻击者猜中生成令牌 (以及不打算由最终用户处理的其他凭据) 的概率必须小于或等于 2^(-128), 并且应当小于或等于 2^(-160).

授权服务器必须利用其他方式保护供最终用户使用的凭据.

10.11. 钓鱼攻击

本协议及类似协议的广泛部署可能让最终用户习惯于被重定向到要求其输入密码的网站. 如果最终用户在输入凭据前不谨慎验证这些网站的真实性, 攻击者就可能利用这种做法窃取资源所有者的密码.

服务提供商应当尝试教育最终用户了解钓鱼攻击带来的风险, 并提供机制让最终用户容易确认其站点的真实性. 客户端开发者应当考虑其与用户代理交互方式 (例如外部或嵌入式) 的安全影响, 以及最终用户验证授权服务器真实性的能力.

为降低钓鱼攻击风险, 授权服务器必须要求所有用于最终用户交互的端点使用 TLS.

10.12. 跨站请求伪造

跨站请求伪造 (Cross-Site Request Forgery, CSRF) 是一种攻击, 攻击者使受害最终用户的用户代理跟随恶意 URI (例如作为误导性链接, 图片或重定向提供给用户代理) 到达受信任服务器 (通常通过有效会话 Cookie 的存在建立信任).

针对客户端重定向 URI 的 CSRF 攻击允许攻击者注入自己的授权码或访问令牌, 这可能导致客户端使用与攻击者受保护资源关联的访问令牌, 而不是受害者的访问令牌 (例如将受害者的银行账户信息保存到攻击者控制的受保护资源中).

客户端必须为其重定向 URI 实现 CSRF 保护. 通常的做法是要求发送到重定向 URI 端点的任何请求都包含一个值, 该值将请求绑定到用户代理的已认证状态 (例如用于认证用户代理的会话 Cookie 的哈希). 客户端在发起授权请求时应当使用 "state" 请求参数将此值传递给授权服务器.

从最终用户获得授权后, 授权服务器将最终用户的用户代理连同 "state" 参数中包含的必需绑定值重定向回客户端. 该绑定值使客户端能够通过将绑定值与用户代理的已认证状态进行匹配来验证请求有效性. 用于 CSRF 保护的绑定值必须包含不可猜测的值 (如第 10.10 节所述), 并且用户代理的已认证状态 (例如会话 Cookie, HTML5 本地存储) 必须保存在只有客户端和用户代理可访问的位置 (即受同源策略保护).

针对授权服务器授权端点的 CSRF 攻击可能导致攻击者在未让最终用户参与或警觉的情况下, 为恶意客户端获得最终用户授权.

授权服务器必须为其授权端点实现 CSRF 保护, 并确保恶意客户端无法在资源所有者不知情且未明确同意的情况下获得授权.

10.13. 点击劫持

在点击劫持攻击中, 攻击者注册一个合法客户端, 然后构造恶意站点, 在其中将授权服务器的授权端点网页加载到透明 iframe 中, 覆盖在一组虚假按钮上方; 这些虚假按钮经过精心构造, 正好位于授权页面的重要按钮下方. 当最终用户点击误导性的可见按钮时, 实际上是在点击授权页面上的不可见按钮 (例如 "Authorize" 按钮). 这允许攻击者在最终用户不知情的情况下诱骗资源所有者授予其客户端访问权限.

为防止这种攻击, 原生应用程序在请求最终用户授权时应当使用外部浏览器, 而不是在应用程序中嵌入浏览器. 对于多数较新的浏览器, 授权服务器可以使用 (非标准的) "x-frame-options" 头来强制避免 iframe. 该头可以有两个值, "deny" 和 "sameorigin", 分别阻止任何框架嵌入, 或阻止不同源站点的框架嵌入. 对于较旧浏览器, 可以使用 JavaScript frame-busting 技术, 但它可能并非在所有浏览器中都有效.

10.14. 代码注入和输入验证

当应用程序未经清理地使用输入或其他外部变量, 并导致应用程序逻辑被修改时, 就会发生代码注入攻击. 这可能允许攻击者访问应用程序设备或其数据, 造成拒绝服务, 或引入多种恶意副作用.

授权服务器和客户端必须清理 (并在可能时验证) 收到的任何值, 尤其是 "state" 和 "redirect_uri" 参数的值.

10.15. 开放重定向器

授权服务器, 授权端点和客户端重定向端点可能配置不当并作为开放重定向器运行. 开放重定向器是指使用某个参数自动将用户代理重定向到该参数值指定的位置, 而不进行任何验证的端点.

开放重定向器可用于钓鱼攻击, 或被攻击者利用熟悉且受信任目标的 URI authority 组件诱使最终用户访问恶意站点. 此外, 如果授权服务器允许客户端仅注册重定向 URI 的一部分, 攻击者可以利用客户端运行的开放重定向器构造一个能通过授权服务器验证, 但会把授权码或访问令牌发送到攻击者控制端点的重定向 URI.

10.16. 在隐式流程中误用访问令牌冒充资源所有者

对于使用隐式流程的公共客户端, 本规范未提供任何方法让客户端确定访问令牌是签发给哪个客户端的.

资源所有者可能由于钓鱼或其他借口, 自愿通过向攻击者的恶意客户端授予访问令牌来委托对资源的访问. 攻击者也可能通过其他机制窃取令牌. 随后攻击者可能通过向合法公共客户端提供该访问令牌来尝试冒充资源所有者.

在隐式流程 (response_type=token) 中, 攻击者可以轻易替换授权服务器响应中的令牌, 用先前签发给攻击者的令牌替换真实访问令牌.

与原生应用程序通信的服务器如果依赖通过后向信道传入的访问令牌来识别客户端用户, 也可能遭到类似破坏, 即攻击者创建一个被攻破的应用程序, 能够注入任意被盗访问令牌.

任何假设只有资源所有者才能向其提交该资源有效访问令牌的公共客户端, 都容易受到此类攻击.

这种攻击可能向攻击者 (恶意客户端) 暴露合法客户端上有关资源所有者的信息. 它还允许攻击者在合法客户端上以最初授予访问令牌或授权码的资源所有者相同权限执行操作.

将资源所有者认证给客户端不在本规范范围内. 任何将授权过程用作向客户端委托最终用户认证形式的规范 (例如第三方登录服务), 如果没有额外安全机制使客户端能够判断访问令牌是否签发给自己使用 (例如对访问令牌进行受众限制), 都禁止使用隐式流程.