Rails 8.1.4.1 一次补 21 个安全问题:上传文件的后缀能左右 ffmpeg

Rails 8.1.4.1 一次补 21 个安全问题:上传文件的后缀能左右 ffmpeg

7小时前
duguying
2 阅读
来源:GitHub

Rails 同日发布 8.1.4.1 与 8.0.5.2,共 21 个 GHSA:上传扩展名可触达 AviSynth 注入、safe_constantize 可被远程 ReDoS,会话 cookie 的 SameSite 也补齐了。

相关标签

#GitHub#Trending#Rails#安全#Ruby

一次补丁版本里塞进 21 个安全公告

11 月 4 日,Rails 同时放出 8.1.4.1 与 8.0.5.2。这两个版本号只多了最后一位,但变更说明里带着 21 个不同的 GHSA 编号——对一个以”约定优于配置”著称的框架来说,这种密度的安全发布并不常见,而且其中好几项直指默认配置下的行为。

上传文件名的后缀能左右 ffmpeg

最值得先看的是 Active Storage 的两处。ActiveStorage::Blob#open 过去会按上传者给的文件名(含扩展名)命名临时文件,于是”只根据扩展名选解码器”的工具就会听上传者的话:发布说明点名了 FFmpeg 的 AviSynth 解复用器——一个 .avs 后缀的临时文件,会让 FFmpeg 去执行文件内容里的指令。现在扩展名只在它与 blob 记录的媒体类型相符时才保留,否则丢弃。

第二处是给 ffmpeg 与 ffprobe 的每次调用都加上 -format_whitelist,把可选的解复用器限制在常见音视频容器内。默认名单之外(MXF、DV、AC3、WavPack、AU、W64,以及裸 H.264 / MPEG-1⁄2 流)的文件将无法生成预览,分析也不再写入媒体元数据,只留一条警告。需要保留的格式要显式加回去:config.active_storage.ffmpeg_allowed_formats += %w[ mxf ]。

三个”引号没转义”的连锁问题

Action View 这一组是典型的字符串拼接后遗症:

  • strip_tags 返回 html_safe 字符串,却没编码引号。现在 &、<、>、"、' 五个字符统一编码。代价是输出出现在纯文本模板或 JSON 里时会看到 &quot; 与 &#39;,需要 CGI.unescapeHTML 还原。
  • highlight 的 :highlighter 模板中,匹配到的文本被原样塞进每个 \1。若匹配内容含引号,就会提前闭合文档里 '<a href="search?q=\1">\1</a>' 这类属性值并注入新属性。现在每个替换组都过一遍 ERB::Util.html_escape_once,且只展开 \0–\9 编号占位符。
  • tag 系列助手对”转成字符串后为空”的属性名不再输出。:" " 这种 Symbol 不算 blank(Symbol#blank? 等同 empty?),此前会走到转义步骤,产出一个没有名字的属性;asset 助手会把 key 符号化,普通 String key 也能走到同一处。

之上还有一层依赖约束:要求 rails-html-sanitizer 1.7.2 以上(连带 Loofah 2.25.3、Nokogiri 1.19.5)。原因是旧版 Nokogiri 的 HTML5 sanitizer 不转义属性值里的 < 和 >,而 highlight、simple_format 是在字符串层面继续编辑已净化的 HTML,属性值里的标记就可能变成活的元素。

反序列化与正则

ActiveSupport::MessagePack 不再把”已不是 html_safe”的 SafeBuffer(比如被就地 gsub! 改过)反序列化成 html_safe。这类缓冲现在以不安全标记序列化、反序列化成普通 String。注意兼容性陷阱:旧版本 Rails 读不了这种新编码,滚动升级时新旧进程混跑会踩到。

ActiveSupport::Inflector#safe_constantize 则把 LoadError 消息里的常量名当字面量匹配,不再拿它拼正则。原来名字的每一段都未转义地插进模式,而能到达这里的输入包括 Action Cable 订阅命令里的 channel 标识符——这是一个可远程触发的 ReDoS 面。

会话与缓存

Action Pack 修的问题更偏”配置看着生效其实没生效”:

  • config.action_dispatch.cookies_same_site_protection 过去只对 CookieStore 生效,CacheStore、MemCacheStore 以及基于 AbstractStore 的第三方 store 发出的会话 cookie 根本没有 SameSite 属性。
  • CacheStore 会话在并发 reset_session 或服务端删除之后仍会被写回,导致旧 session ID 复活。
  • 跳过 session 的响应(如 Active Storage 代理那种可公开缓存的响应)本不该带 Set-Cookie,但密钥轮换后会顺手把升级格式的 cookie 写回去。
  • Vary: Accept 只在请求本身带可用 Accept 时才加。少了这个头,共享缓存可能把一份 HTML 响应喂给后来请求 JavaScript 表示的客户端。现在只要格式不由 URL 决定,响应就按 Accept 与 X-Requested-With 变化;无 Accept 的 XHR 还要加 Content-Type。
  • ActionController::Live 的流在缓冲区写满后被关闭或中断时会阻塞,已修。

另外 Action Mailbox 开始拒绝时间戳比本地时间超前 2 分钟以上的 Mailgun 入站邮件。

该怎么做

这不是可以排队到下个迭代的版本。21 个公告里既有可远程触发的 ReDoS,也有上传路径上的命令注入面,还有会话与缓存语义漏洞。升级顺序建议:先 bundle update rails 到 8.1.4.1 或 8.0.5.2,再单独确认 rails-html-sanitizer 是否已到 1.7.2;有多进程混跑的部署,把 MessagePack 编码变更当作一次需要同步重启的迁移来对待。

仓库地址:https://github.com/rails/rails

返回列表

更多资讯

想看更多优质内容?

浏览所有资讯