Проверьте tar-архив перед извлечением

В документации по Python рекомендуется не извлекать tar-архив без предварительной проверки. Каков наилучший способ убедиться, что архив безопасен, используя модуль tarfile python? Должен ли я просто перебирать все имена файлов и проверять, содержат ли они абсолютные пути?

Будет ли достаточно следующего?

import sys
import tarfile
with tarfile.open('sample.tar', 'r') as tarf:
    for n in tarf.names():
        if n[0] == '/' or n[0:2] == '..':
            print 'sample.tar contains unsafe filenames'
            sys.exit(1)
    tarf.extractall()

Редактировать

Этот скрипт несовместим с версиями до 2.7. cf с и tarfile.

Теперь я перебираю членов:

target_dir = "/target/"
with closing(tarfile.open('sample.tar', mode='r:gz')) as tarf:
    for m in tarf:
        pathn = os.path.abspath(os.path.join(target_dir, m.name))
        if not pathn.startswith(target_dir):
            print 'The tar file contains unsafe filenames. Aborting.'
            sys.exit(1)
        tarf.extract(m, path=tdir)

person hpixel    schedule 13.11.2011    source источник


Ответы (1)


Почти, хотя путь вроде foo/../../ все равно можно было бы иметь.

Лучше было бы использовать os.path.join и os.path.abspath, которые вместе будут правильно обрабатывать ведущие / и .. в любом месте пути:

target_dir = "/target/" # trailing slash is important
with tarfile.open(…) as tarf:
    for n in tarf.names:
        if not os.path.abspath(os.path.join(target_dir, n)).startswith(target_dir):
            print "unsafe filenames!"
            sys.exit(1)
    tarf.extractall(path=target_dir)
person David Wolever    schedule 13.11.2011
comment
Спасибо за трюк с абспатом. Теперь я предпочитаю перебирать членов и использовать tarf.extract(member, path=target_dir), потому что кажется, что архив полностью прочитан tarf.getnames(). - person hpixel; 13.11.2011
comment
Это работает. Вы также можете использовать tarf.seek(0), а затем extractall(). - person David Wolever; 13.11.2011
comment
Кроме того, если этот ответ был полезен, подумайте о том, чтобы проголосовать и принять его. - person David Wolever; 13.11.2011
comment
Ах, да, я забыл, что голосовать за 15 или 25 повторений, а не за 10. Кроме того, добро пожаловать в StackOverflow :) - person David Wolever; 13.11.2011