如何保护自己免受gzip或bzip2炸弹的攻击?

2024-10-05 19:28:17 发布

您现在位置:Python中文网/ 问答频道 /正文

这与问题about zip bombs有关,但考虑到gzip或bzip2压缩,例如接受.tar.gz文件的web服务。在

Python提供了一个方便使用的tarfile module,但似乎没有提供针对zipbomb的保护。在

在使用tarfile模块的python代码中,检测zip炸弹最优雅的方法是什么,最好不要从tarfile模块复制太多的逻辑(例如透明的解压缩支持)?在

而且,简单一点:不涉及真正的文件;输入是一个类似文件的对象(由web框架提供,代表用户上传的文件)。在


Tags: 模块文件代码webtarzipaboutmodule
3条回答

可以使用^{} module限制进程及其子进程的可用资源。在

如果需要在内存中解压缩,则可以设置resource.RLIMIT_AS(或RLIMIT_DATARLIMIT_STACK),例如使用上下文管理器将其自动还原为以前的值:

import contextlib
import resource

@contextlib.contextmanager
def limit(limit, type=resource.RLIMIT_AS):
    soft_limit, hard_limit = resource.getrlimit(type)
    resource.setrlimit(type, (limit, hard_limit)) # set soft limit
    try:
        yield
    finally:
        resource.setrlimit(type, (soft_limit, hard_limit)) # restore

with limit(1 << 30): # 1GB 
    # do the thing that might try to consume all memory

如果达到限制;MemoryError将被提升。在

如果您是为linux开发的,那么可以在单独的进程中运行解压,并使用ulimit来限制内存使用。在

import subprocess
subprocess.Popen("ulimit -v %d; ./decompression_script.py %s" % (LIMIT, FILE))

记住减压_脚本.py在写入磁盘之前,应将整个文件解压缩到内存中。在

这将确定gzip流的未压缩大小,同时使用有限的内存:

#!/usr/bin/python
import sys
import zlib
f = open(sys.argv[1], "rb")
z = zlib.decompressobj(15+16)
total = 0
while True:
    buf = z.unconsumed_tail
    if buf == "":
        buf = f.read(1024)
        if buf == "":
            break
    got = z.decompress(buf, 4096)
    if got == "":
        break
    total += len(got)
print total
if z.unused_data != "" or f.read(1024) != "":
    print "warning: more input after end of gzip stream"

提取时,它将返回中tar文件中所有文件所需空间的略微高估。长度包括这些文件以及tar目录信息。在

在gzip.py代码不控制解压的数据量,除非根据输入数据的大小。在gzip.py,它一次读取1024个压缩字节。所以你可以用gzip.py如果您可以为未压缩的数据使用最多1056768字节的内存(1032*1024,其中1032:1是deflate的最大压缩比)。这里的解决方案将zlib.decompress与第二个参数一起使用,这限制了未压缩数据的数量。gzip.py没有。在

这将通过解码tar格式准确地确定提取的tar条目的总大小:

^{pr2}$

你可以用它的变体来扫描tar文件中的炸弹。这样做的好处是,在您甚至还没有解压缩数据之前,就可以在头信息中找到一个大的大小。在

至于。焦油bz2归档文件中,pythonbz2库(至少在3.3版本中)对于bz2炸弹消耗太多内存来说不可避免地是不安全的。bz2.decompress函数不像zlib.decompress那样提供第二个参数。由于运行长度编码,bz2格式的最大压缩比比zlib高得多,这使得情况变得更糟。bzip2将1gb的零压缩到722字节。因此,即使没有第二个参数,也不能像使用zlib.decompress那样,通过测量输入来测量bz2.decompress的输出。对解压输出大小没有限制是Python接口的一个基本缺陷。在

我查看了3.3中的bz2module.c,看看是否有一种没有文档记录的方法来使用它来避免这个问题。没有办法绕过它。其中的decompress函数只是不断增加结果缓冲区,直到它可以解压缩所有提供的输入。_bz2module.c需要修复。在

相关问题 更多 >