You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过boost::iostream防范Zip炸弹?代码安全问题咨询

Boost::iostreams Gzip解压与Zip炸弹防护问题

1. 遇到Zip炸弹会导致内存耗尽/进程崩溃吗?

绝对会!你这段代码完全没做解压后的数据量限制——要是输入是个Zip炸弹(比如几KB的压缩包能解压出几十GB甚至更大的数据),back_inserter会持续往decompressed向量里写入数据,直到系统内存被彻底耗尽。最终要么进程被系统的OOM(内存不足)杀手强制终止,要么因为内存分配失败直接崩溃。毕竟vector会无限制自动扩容,完全没有上限约束,这正好给了Zip炸弹可乘之机。

2. 怎么防范这种风险?

这里有几个实用的防护方案,按优先级推荐:

  • 设置解压大小上限(最可靠):自定义一个输出流过滤器,在写入数据时实时累计字节数,一旦超过预设的安全上限就抛出异常,中断解压流程。比如写个简单的限流过滤器:
    class limit_output_filter : public boost::iostreams::output_filter {
    public:
        explicit limit_output_filter(std::size_t max_size) 
            : max_size_(max_size), current_size_(0) {}
    
        template<typename Sink>
        bool put(Sink& snk, char c) {
            if (current_size_ >= max_size_) {
                throw std::runtime_error("Decompressed data exceeds allowed size limit");
            }
            ++current_size_;
            return boost::iostreams::put(snk, c);
        }
    
    private:
        std::size_t max_size_;
        std::size_t current_size_;
    };
    
    然后把这个过滤器加到你的解压链最前面:
    std::vector<char> unzip(std::vector<char> const& compressed, std::size_t max_decompressed_size) {
        std::vector<char> decompressed;
        boost::iostreams::filtering_ostream os;
        // 先加限流过滤器,把住数据量的第一道关
        os.push(limit_output_filter(max_decompressed_size));
        os.push(boost::iostreams::gzip_decompressor());
        os.push(boost::iostreams::back_inserter(decompressed));
        try {
            boost::iostreams::write(os, &compressed[0], compressed.size());
            os.reset();
        } catch (const std::runtime_error& e) {
            // 处理超限情况,比如清空向量后抛出异常,或者返回空向量
            decompressed.clear();
            throw;
        }
        return decompressed;
    }
    
  • 结合压缩比校验:在解压过程中实时计算压缩比(解压后大小/压缩前大小),如果超过一个合理的阈值(比如100:1,具体根据你的业务场景调整)就中断解压。不过要注意,有些合法数据(比如全是0的文件)也可能有高压缩比,所以这个方法最好和大小上限配合使用,不要单独依赖。
  • 改用流式处理:如果业务允许,不要把整个解压后的数据都加载到内存的vector里,而是边解压边处理(比如分块写入文件、或者逐块处理业务逻辑),这样能避免一次性占用大量内存,从根源上降低OOM风险。

3. 能不能在解压前拿到原始数据的大小?

很遗憾,对于gzip格式来说,没有可靠的方法在完全解压前获取准确的原始数据大小:

  • gzip头部并不存储未压缩数据的总大小,只有在压缩包的尾部有4字节的未压缩长度字段,但这个字段仅当未压缩数据小于4GB时有效;如果数据超过4GB,这个值是截断后的,完全不准确。
  • 更关键的是,这个尾部的长度字段可以被恶意篡改(比如Zip炸弹会伪造一个很小的数值,实际解压后却超大),所以就算能解析出来,也不能信任这个值来做内存分配或者限流。

所以,别指望提前获取大小来规避风险,最靠谱的还是在解压过程中动态限制数据量。


内容的提问来源于stack exchange,提问作者alpha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:07:59