Caddy SSO插件安全漏洞分析
背景介绍
Caddy(又称Caddy Server或Caddy 2)是一个用Golang编写的现代开源Web服务器,设计易于使用且高度可配置。Caddy旨在简化托管Web应用程序的过程,同时优先考虑安全性和性能。它致力于减少配置和部署Web服务器的复杂性。
caddy-security插件是Caddy Web服务器的中间件插件,提供各种安全相关功能以增强Web应用程序的整体安全态势。该插件的主要功能包括:基于表单、基本、本地、LDAP、OpenID Connect、OAuth 2.0、SAML认证的认证插件,以及基于JWT/PASETO令牌的HTTP请求授权插件。
发现的安全问题
问题 #1:反射型跨站脚本(XSS)
严重性:高
反射型XSS发生在应用程序将不受信任的数据包含在发送到用户浏览器的HTML响应中。在这种情况下,提供的/admin%22%3E%3Cscript%3Ealert(document.domain)%3C/script%3E/admin/login或/settings/mfa/delete/<img%20src=x%20onerror=alert(document.domain)> API调用会触发警报。攻击者可利用此漏洞在目标用户的浏览器中执行任意JavaScript代码,可能导致进一步的攻击,如会话劫持。
即时修复方案: 将所有字符串值策略性地视为可能不可信,无论其来源如何,并正确转义(使用生成输出安全HTML的safehtml/template包)。
长期建议:
- 使用潜在恶意的XSS有效载荷扩展单元测试
- 在测试环境中对所有API调用使用Burp Suite Professional的主动扫描器
- 扩展caddy-security文档以推广安全头,特别是内容安全策略(CSP)头
问题 #2:不安全随机数生成
严重性:高
caddy-security插件使用基于Unix时间戳种子的math/rand Golang库为应用程序中的三个安全关键上下文生成字符串,这可能通过暴力搜索预测。攻击者可能使用OAuth流中用于认证目的的潜在可预测nonce值进行OAuth重放攻击。
即时修复方案: 使用加密安全的随机数生成器生成随机字符串。Golang的crypto/rand库专为安全随机数生成而设计。
长期建议:
- 审查应用程序中其他使用math/rand包的安全上下文
- 避免代码重复,使用单一安全函数
- 在CI/CD中实施Semgrep
问题 #3:通过X-Forwarded-For头进行IP欺骗
严重性:中
通过操纵X-Forwarded-For头,攻击者可以欺骗用户身份模块(/whoami API端点)中使用的IP地址。如果系统信任此欺骗IP地址,可能导致未经授权的访问。
修复方案: 重新实现应用程序,在获取用户IP地址时不依赖用户提供的头。如果需要用户提供的头,确保正确验证头值。
问题 #4:基于Referer头的XSS
严重性:中
通过重写Referer头可以触发XSS漏洞。虽然Referer头通过转义某些允许XSS的字符进行了清理,但没有考虑基于JavaScript URL方案(如javascript:alert(document.domain)// payload)的攻击。
修复方案: 与问题#1相同。
问题 #5:开放重定向漏洞
严重性:中
当登录用户点击带有redirect_url参数的特制链接时,用户可能被重定向到外部网站。这可能导致钓鱼攻击。
修复方案: 执行适当的redirect_url参数验证,确保重定向URL仅允许在同一域内或来自受信任源。
问题 #6:X-Forwarded-Host头操纵
严重性:中
caddy-security插件处理X-Forwarded-Host头,可能导致各种安全漏洞(Web缓存中毒、业务逻辑缺陷、基于路由的服务器端请求伪造[SSRF]和经典服务器端漏洞)。
修复方案: 不要依赖Host和X-Forwarded-Host头,而是使用配置文件中手动指定的当前域生成QR码。
问题 #7:X-Forwarded-Proto头操纵
严重性:低
处理X-Forwarded-Proto头会导致重定向到注入的协议。虽然此场景影响有限,但不正确处理此类头可能导致不可预测的安全风险。
修复方案: 不要依赖X-Forwarded-Proto头。如果需要,根据接受的协议允许列表验证X-Forwarded-Proto头的值。
问题 #8:通过暴力破解验证码绕过2FA
严重性:低
应用程序的双因素认证(2FA)当前实现缺乏对暴力攻击的充分保护。
修复方案: 在MFA配置中强制执行最少六位代码长度,实施账户锁定机制,并对关键操作强制重新认证。
问题 #9:注销时缺乏用户会话失效
严重性:低
caddy-security插件在点击"Sign Out"按钮时缺乏适当的用户会话失效;即使用户发送了/logout和/oauth2/google/logout请求,用户会话仍然有效。
修复方案: 审查注销过程以识别意外行为的原因,确保/oauth2/google/logout端点正确终止用户会话并使相关令牌失效。
问题 #10:解析Caddyfile时的多个Panic
严重性:低
多个解析函数在尝试访问元素之前不验证其输入值是否为nil,这可能导致panic(索引越界)。
修复方案: 在所有相关函数中,在元素访问之前集成nil检查。
Golang社区安全
我们在Trail of Bits热爱编写和审查Golang代码库。我们不断致力于Golang相关的(Semgrep)资源、规则和博客文章,并期待任何机会承担宠物审计(如此次)和客户项目,在这些项目中我们检查Golang代码库。
我们发布这些发现的目的是帮助保护其他可能考虑实施与我们探索的解决方案类似的人,并帮助他们就安全基础设施做出明智决策。
协调披露时间线
作为披露过程的一部分,我们首先向caddy-security插件维护者报告了漏洞:
- 2023年8月7日:向caddy-security插件维护者报告了我们的发现
- 2023年8月23日:caddy-security插件维护者确认没有近期计划对报告的漏洞采取行动
- 2023年9月18日:披露博客文章发布,问题已提交到原始项目仓库