ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

为什么不要用 Ruby Marshal.load 反序列化不可信数据?安全的替代方案是什么?

为什么不要用 Ruby Marshal.load 反序列化不可信数据?安全的替代方案是什么? 为什么不要用 Ruby Marshal.load 反序列化不可信数据安全的替代方案是什么【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby如果你的 Ruby 程序需要从外部来源缓存、消息队列、用户上传、持久化文件等读回二进制数据并还原成 Ruby 对象Ruby 官方安全文档给出的结论很直接不要用Marshal.load反序列化不可信或用户提供的数据改用的方式是 doc/security/security.rdoc。这篇文章说明它为什么危险、机制出在哪里以及如何把现有的Marshal.load路径替换成文档推荐的做法。为什么 Marshal.load 对不可信数据危险doc/security/security.rdoc 的Marshal.load一节给出了三点事实依据Marshal模块可以把 Ruby 对象树序列化成二进制格式也可以从该格式反序列化回来Marshal可以反序列化出几乎任何 Ruby 对象并且对实例变量有完全控制权正因为如此攻击者可以构造一个恶意 payload使其在反序列化完成后不久就执行代码。具体机制可以在 doc/language/marshal.rdoc 的格式文档里找到。Marshal 格式除了表示基本类型外还有三种用户定义的扩展机制都会把「读取数据」变成「调用代码」o类型Object流里携带类名和若干「实例变量名 值」对反序列化时按类名还原对象并设置其实例变量——这正是 security.rdoc 说的「对实例变量有完全控制权」u类型User Defined携带类名和自定义字节数据反序列化时会在该类上调用类方法_loadU类型User Marshal反序列化时分配新实例并调用其实例方法marshal_load此外d类型Data在 load 一个 C 扩展 Data 对象时会调用扩展的_load_data。也就是说一段恶意二进制流只要触发上述任意一条路径就能在你认为只是「读数据」的时刻执行任意逻辑。这类漏洞在 Ruby 生态里属于公开 CVE 的常见来源CVE 列表和漏洞报告方式securityruby-lang.org私有邮件列表见 doc/security/security.rdoc 开头部分。安全替代用 JSON 处理不可信数据security.rdoc 给出的替代方案是如果需要反序列化不可信数据应使用 JSON因为它只能返回字符串、数组、hash、数字和nil这类「原始」类型不会构造任意对象。典型写法如下require json data JSON.parse(untrusted_payload) # data 中只可能出现字符串、数组、hash、数字和 nil文档同时给出了两条限制条件替换时要一并落实如果业务上确实需要还原 JSON 之外的类即需要结构化对象应手动处理把解析出的基本类型数据在代码里组装成你的对象永远不要反序列化到用户指定的类never deserialize to a user specified class。顺带排查同类风险YAML同一份安全文档指出YAML 存在与 Marshal 类似的问题它同样能反序列化出任意 Ruby 类。文档给出的示例文档示例原文如此是这段 YAML 数据在反序列化时会创建一个ERB对象!ruby/object:ERB src: puts uname因此文档的结论是不要用 YAML 反序列化不可信数据适用于 Marshal 的大部分安全考量同样适用于 YAML。如果你的程序里存在对用户可控内容的unsafe_load调用应和Marshal.load一起排查替换。结果验证与判断标准替换完成后可以用文档中明确的性质来核对新路径解析不可信数据的结果中只应出现字符串、数组、hash、数字和nil——这是 security.rdoc 对 JSON 的明确描述一旦逻辑里假设了其他对象类型说明仍然依赖了不安全的路径应改为手动组装对照 doc/language/marshal.rdoc 的格式说明可知若流中引用的类或模块不存在「应当抛出异常」Struct 名称或成员数不匹配时同样应当抛异常。这类异常行为说明格式本身依赖当前进程里已加载的类定义进一步印证了它不适合承载外部数据。可选加固Ruby 3.1 的freeze: true选项doc/NEWS/NEWS-3.1.0.md 记录了Marshal在 3.1 的一个变更Marshal.loadnow accepts afreeze: trueoption. All returned objects are frozen except forClassandModuleinstances. Strings are deduplicated.如果数据源确实完全可信、你只是想让 load 出来的对象不可变可以在 Ruby 3.1 及以后加上该选项。注意 security.rdoc 的结论没有因此改变——对不可信数据仍然不应使用Marshal.loadfreeze: true不能替代改用 JSON 这一主路径。小结不可信/用户提供的数据Marshal.load一律不用改用JSON.parse得到基本类型需要对象时在代码里手动组装不允许按用户输入决定目标类对用户可控内容的 YAMLunsafe_load属于同类风险一并处理完整论述见 doc/security/security.rdoc二进制格式细节见 doc/language/marshal.rdoc。【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表