Spring Security OAuth 2.3 开放重定向漏洞(CVE-2019-3778)分析与复现
漏洞概述
漏洞名称:Spring Security OAuth 开放重定向漏洞
CVE编号:CVE-2019-3778
漏洞类型:开放重定向
威胁等级:中危(Medium)
影响范围:
- Spring Security OAuth 2.3 至 2.3.4
- Spring Security OAuth 2.2 至 2.2.3
- Spring Security OAuth 2.1 至 2.1.3
- Spring Security OAuth 2.0 至 2.0.16
- 更早的不受支持版本也受影响
漏洞描述
该漏洞存在于Spring Security OAuth的实现中,恶意攻击者可以构造特殊请求发送到使用"授权码"类型授权的端点,通过操纵"redirect_uri"参数控制重定向URI。这会导致授权服务器将用户代理重定向到攻击者控制的URI,可能导致授权码泄露。
前置知识
OAuth 2.0简介
OAuth协议为用户资源授权提供了安全、开放且简易的标准。与传统的授权方式不同,OAuth授权不会让第三方接触到用户的账号信息(如用户名和密码),第三方无需使用用户的凭证就可以获得该用户资源的授权。
Spring Security OAuth
Spring Security是一个安全框架,前身是Acegi Security,能够为Spring企业应用系统提供声明式的安全访问控制。它基于Servlet过滤器、IoC和AOP,为Web请求和方法调用提供身份确认和授权处理。
OAuth 2.0授权模式
- 简化模式(Implicit):适用于纯静态页面应用
- 授权码模式(Authorization Code):适用于有自己的服务器的应用
- 密码模式(Resource Owner Password Credentials):用户直接向客户端提供用户名和密码
- 客户端模式(Client Credentials):适用于后端模块或高度信任的客户端
漏洞复现
复现条件
- 使用存在漏洞的Spring Security OAuth2版本
- OAuth认证使用授权码模式
- 用户处于已登录状态
环境搭建
- 下载存在漏洞版本的Spring Security OAuth:
https://github.com/spring-projects/spring-security-oauth/releases - 参考示例项目搭建测试环境:
https://github.com/oktadeveloper/okta-spring-boot-authz-server-example
漏洞验证步骤
-
正常请求:发送包含有效redirect_uri的请求
/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://valid-redirect.com系统会正常验证redirect_uri参数
-
恶意请求1:修改redirect_uri为攻击者控制的域名
/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://attacker.com系统会检测到非法redirect_uri并拒绝请求
-
恶意请求2:在恶意redirect_uri中添加百分号"%"
/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://attacker.com%此时系统会绕过验证,将用户重定向到攻击者控制的网站
漏洞分析
问题代码位置
漏洞存在于org.springframework.security.oauth2.provider.endpoint.DefaultRedirectResolver类的obtainMatchingRedirect方法中。
根本原因
该方法在处理用户输入的redirect_url参数时,校验机制不够严格,未对"%"这类特殊字符进行适当处理,导致可以通过添加百分号绕过重定向URL的验证。
修复方案
各版本用户应升级到以下修复版本:
- 2.3.x用户升级到2.3.5
- 2.2.x用户升级到2.2.4
- 2.1.x用户升级到2.1.4
- 2.0.x用户升级到2.0.17
- 更早版本应升级到受支持的分支
安全建议
- 及时升级到修复版本
- 在自定义实现OAuth协议时,应对所有用户输入参数进行严格验证
- 遵循"不信任用户输入"原则,对所有来自用户的参数进行充分检查
- 实施白名单机制验证redirect_uri,而非简单的字符串匹配
总结
该漏洞展示了即使在使用成熟安全框架时,也需要对用户输入保持警惕。开发者在实现安全协议时应特别注意参数验证逻辑,避免因校验不严导致的安全问题。