
Tornado 6.3.2 安全修复解析StaticFileHandler 开放重定向漏洞的成因、修复与验证【免费下载链接】tornadoTornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.项目地址: https://gitcode.com/gh_mirrors/to/tornado导读本文围绕 Tornado 6.3.2发布于 2023 年 5 月 13 日的唯一一项变更展开修复StaticFileHandler在特定配置下存在的开放重定向open redirect漏洞。我们将从漏洞的协议原理入手结合 tornado/web.py 中的修复实现与 tornado/test/web_test.py 中的回归测试还原漏洞触发条件、修复策略与验证方法帮助读者理解静态文件服务场景下的 URL 安全边界并给出可落地的排查与升级建议。Tornado 6.3.2一次聚焦安全的补丁版本Tornado 6.3.2 是 6.3 系列的一个维护版本发布说明极其精炼核心内容仅一条Fixed an open redirect vulnerability in StaticFileHandler under certain configurations.修复了 StaticFileHandler 在特定配置下的开放重定向漏洞对比相邻版本6.3.1 修复的是RequestHandler.set_cookie对大写关键字参数的兼容性问题6.3.2 的变更范围更集中——它完全围绕静态文件服务的 URL 规范化逻辑展开。该漏洞不是代码注入或路径穿越而是一个HTTP 重定向语义问题在满足特定配置组合时攻击者可以诱导服务器发出指向任意外部主机的 302/301 重定向进而用于钓鱼、凭据窃取等攻击场景。什么是开放重定向Open Redirect开放重定向指服务器在收到请求后将用户重定向到攻击者可控的外部 URL。其危害在于浏览器地址栏中的域名仍是受害站点用户会误以为链接可信从而在钓鱼页面上泄露敏感信息。Tornado 的RequestHandler.redirect()见 tornado/web.py本身允许相对或绝对 URL因此框架层面对重定向目标并无白名单约束——安全责任落在生成重定向目标的调用方身上。在 6.3.2 之前的StaticFileHandler中当请求一个不带尾斜杠的目录路径且配置了默认首页文件时处理器会执行self.redirect(self.request.path /, permanentTrue)即把/static/dir301 重定向到/static/dir/。该重定向目标是请求路径原样拼接斜杠于是问题转化为请求路径能否被构造得形如//evil.com/...这正是本漏洞的关键——//开头的路径在浏览器中会被解析为协议相对 URLprotocol-relative URL例如Location: //evil.com/static/dir/会被浏览器当作https://evil.com/static/dir/处理从而将用户引导至攻击者控制的站点。漏洞触发条件三项配置缺一不可根据 tornado/test/web_test.py 中回归测试的注释漏洞只在满足以下全部条件的特定配置下可被利用条件说明对应配置1静态 URL 前缀为/根路径static_url_prefix/2设置了目录默认文件static_handler_argsdict(default_filenameindex.html)任意值均可3攻击者已知静态目录在服务器上的近绝对路径例如测试中的os.path.abspath(static)前两项是 Tornado 应用侧的配置组合当static_url_prefix/时路由不再为静态路径保留独立前缀请求路径会原样进入StaticFileHandler的路径校验逻辑default_filename则让目录 无尾斜杠的请求进入重定向分支见 tornado/web.py。第三项是攻击成本——攻击者需要知道服务端静态目录的绝对路径才能构造出既能通过路径包含校验、又能在规范化后变成//host开头的畸形路径例如测试中的//evil.com/../{absolute_static_dir}/static/dir服务器端os.path对路径做规范化和拼接后//evil.com/../...中//evil.com被当作一个普通路径段..回退后落在静态目录内通过了validate_absolute_path的越界检查tornado/web.py但该路径不以尾斜杠结尾且对应一个目录于是进入重定向分支self.request.path /得到//evil.com/../.../dir/写入Location响应头浏览器将//evil.com识别为协议相对 URL 的主机部分把用户重定向到evil.com。值得注意的是此路径并不需要真实存在于磁盘它只需满足规范化后对应一个目录的判定即可因此攻击面相对容易扩大。修复实现在重定向分支前置 403 拦截修复落在 tornado/web.py 的validate_absolute_path方法中紧贴重定向代码之前if not self.request.path.endswith(/): if self.request.path.startswith(//): # A redirect with two initial slashes is a protocol-relative URL. # This means the next path segment is treated as a hostname instead # of a part of the path, making this effectively an open redirect. # Reject paths starting with two slashes to prevent this. # This is only reachable under certain configurations. raise HTTPError( 403, cannot redirect path with two initial slashes ) self.redirect(self.request.path /, permanentTrue) return None修复策略是在触发重定向前显式拒绝任何以//开头的请求路径直接返回 HTTP 403 Forbidden而非发起重定向。从源码注释可以读出两层设计意图语义清晰//开头的路径一旦进入重定向就会变成协议相对 URL属于不可接受的重定向目标因此在源头掐断注释诚实标注适用边界代码注释明确指出 This is only reachable under certain configurations说明该分支与static_url_prefix/等配置强相关并非所有部署都会走到。此外403 响应本身也避免了信息泄露它发生在重定向前攻击者无法再通过重定向 vs 403的行为差异探测静态目录是否存在——这与该方法中_resolve_symlink_target越界时故意返回与路径检查相同错误的设计tornado/web.py一脉相承体现了 Tornado 在路径校验上错误信息不区分内外的安全一致性。回归测试锁定漏洞场景的精确验证static_foo.txt 所在测试目录配合StaticDefaultFilenameRootTest测试类tornado/test/web_test.py完成了对修复的验证def test_no_open_redirect(self): # 6.3.2 之前影响某些配置的开放重定向已不可能再发生 # 漏洞需要 static_url_prefix/ 与 default_filename任意值同时设置 # 并且需要知道静态目录的服务器端绝对路径。 test_dir os.path.dirname(__file__) drive, tail os.path.splitdrive(test_dir) if os.name posix: self.assertEqual(tail, test_dir) else: test_dir tail with ExpectLog(gen_log, .*cannot redirect path with two initial slashes): response self.fetch( f//evil.com/../{test_dir}/static/dir, follow_redirectsFalse, ) self.assertEqual(response.code, 403)测试要点有三处均值得在生产排查时参考测试夹具完全复刻漏洞配置static_pathos.path.abspath(...)配合static_url_prefix/与default_filenameindex.html确保测试覆盖的是真正受影响的那类部署HTTP 客户端特意选用SimpleAsyncHTTPClient测试注释解释了原因——curl 客户端根本不允许发送以两个斜杠开头的请求而simple_httpclient可以这保证畸形请求能真实到达服务器端处理链tornado/test/web_test.py断言 403 且关闭重定向跟随follow_redirectsFalse确保验证的是服务器原始响应ExpectLog同时确认了修复分支中cannot redirect path with two initial slashes的日志路径被实际执行即修复代码真正生效。防御纵深与升级建议针对使用 Tornado 静态文件服务的项目结合本次修复可以沉淀以下实践升级到 6.3.2 及以上版本该修复已进入 6.3.2 及其后的 6.4.x、6.5.x 系列升级是消除漏洞最直接的途径。仓库根目录的 README.rst 与 pyproject.toml 提供了项目安装与版本管理入口。审视自身配置组合若应用同时使用了static_url_prefix/与default_filename应重点核查是否暴露在公开网络测试目录tornado/test/static/dir/index.html与 tornado/test/static/robots.txt 展示了默认静态目录的典型布局便于对照。理解重定向前置检查的必要性RequestHandler.redirect对目标 URL 不做协议白名单任何基于用户可控路径 字符串拼接生成Location的代码都应当自行校验目标拒绝//开头、拒绝javascript:等协议本次修复正是这一原则在框架内部的落实。保持错误行为不泄露内部信息的原则Tornado 在本次修复及 symlink 校验中均刻意让 403 行为一致避免攻击者通过响应差异探测文件系统结构这也是安全加固中值得借鉴的通用做法。小结Tornado 6.3.2 用一行发布说明记录了一次小而关键的安全修复在StaticFileHandler的目录重定向逻辑前拦截//开头的请求路径封堵了由协议相对 URL 引发的开放重定向。通过 tornado/web.py 的修复实现与 tornado/test/web_test.py 的回归测试我们可以完整还原漏洞成因前缀、默认文件、路径拼接三要素、修复策略前置 403与验证手段畸形路径 精确断言。对于所有以 Tornado 提供静态资源的项目这既是一次具体的版本升级提醒也是一份关于重定向目标必须可信的框架级安全教材。【免费下载链接】tornadoTornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed.项目地址: https://gitcode.com/gh_mirrors/to/tornado创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考