Spec-Zone.ru › Perl 5.38

perlsec

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ОПИСАНИЕ
  • КОНТАКТНАЯ ИНФОРМАЦИЯ О ВОЗМОЖНЫХ УЯЗВИМОСТЯХ
  • МЕХАНИЗМЫ И ВОПРОСЫ БЕЗОПАСНОСТИ
    • Режим проверки на загрязнение
    • Отмывание и обнаружение загрязнённых данных
    • Переключатели в строке "#!"
    • Режим проверки на загрязнение и @INC
    • Настройка пути
    • Проблема гонки shebang
    • Защита ваших программ
    • Unicode
    • Атаки на алгоритмическую сложность
    • Использование Sudo
  • СМОТРИТЕ ТАКЖЕ

НАЗВАНИЕ

perlsec - Безопасность Perl

ОПИСАНИЕ

Perl разработан для того, чтобы облегчить безопасное программирование даже при работе с повышенными привилегиями, такими как программы setuid или setgid. В отличие от большинства командных оболочек, которые основаны на нескольких проходах по подстановке для каждой строки скрипта, Perl использует более традиционную схему оценки с меньшим количеством скрытых проблем. Кроме того, поскольку язык имеет больше встроенных функций, он может меньше полагаться на внешние (и, возможно, небезопасные) программы для достижения своих целей.

КОНТАКТНАЯ ИНФОРМАЦИЯ О ВОЗМОЖНЫХ УЯЗВИМОСТЯХ

Если вы считаете, что обнаружили уязвимость в интерпретаторе Perl или модулях, поддерживаемых в ядре Perl, отправьте подробности по адресу perl-security@perl.org. Этот адрес является закрытым почтовым списком, отслеживаемым командой по безопасности Perl.

См. perlsecpolicy для дополнительной информации.

МЕХАНИЗМЫ И ВОПРОСЫ БЕЗОПАСНОСТИ

Режим проверки на загрязнение

По умолчанию Perl автоматически включает набор специальных проверок безопасности, называемых режимом проверки на загрязнение, когда обнаруживает, что его программа выполняется с различными реальными и эффективными идентификаторами пользователя или группы. Бит setuid в разрешениях Unix имеет режим 04000, бит setgid имеет режим 02000; может быть установлен один или оба бита. Вы также можете явно включить режим проверки на загрязнение, используя флаг командной строки -T. Этот флаг настоятельно рекомендуется для серверных программ и любых программ, выполняемых от имени другого пользователя, таких как скрипт CGI. После включения режима проверки на загрязнение он остаётся включённым на протяжении всего остатка вашего скрипта.

В этом режиме Perl принимает особые меры предосторожности, называемые проверками на загрязнение, чтобы предотвратить очевидные и скрытые ловушки. Некоторые из этих проверок достаточно просты, например, проверка того, что каталоги пути не могут быть записаны другими пользователями; внимательные программисты всегда использовали такие проверки. Однако другие проверки лучше всего поддерживаются самим языком, и именно эти проверки в особенности способствуют тому, чтобы программа Perl с установленным идентификатором была более безопасной, чем соответствующая программа на C.

Вы не можете использовать данные, полученные извне вашей программы, для воздействия на что-либо за пределами вашей программы — по крайней мере, не случайно. Все аргументы командной строки, переменные среды, информация о локали (см. perllocale), результаты определённых системных вызовов (readdir(), readlink(), переменная shmread(), сообщения, возвращаемые msgrcv(), пароль, поля gcos и shell, возвращаемые вызовами getpwxxx()), и весь ввод из файлов помечаются как «загрязнённые». Загрязнённые данные нельзя напрямую или косвенно использовать в любой команде, которая вызывает подоболочку, или в любой команде, которая изменяет файлы, каталоги или процессы, за исключением следующих случаев:

Поддержка проверок на загрязнение добавляет нагрузку на все программы Perl, независимо от того, используете ли вы функции проверки на загрязнение. В Perl 5.18 были введены символы препроцессора C, которые можно использовать для отключения функций проверки на загрязнение.

  • Аргументы функций print и syswrite не проверяются на загрязнение.

  • Символьные методы

    $obj->$method(@args);

    и символические подссылки

    &{$foo}(@args);
    $foo->(@args);

    не проверяются на загрязнение. Это требует особой осторожности, если вы не хотите, чтобы внешние данные повлияли на ваш поток управления. Если вы не ограничите значения этих символьных переменных, люди смогут вызывать функции вне вашего кода Perl, такие как POSIX::system, в результате чего они смогут выполнять произвольный внешний код.

  • Ключи словарей никогда не загрязнены.

По соображениям эффективности Perl принимает консервативную точку зрения на то, является ли данные загрязнёнными. Если выражение содержит загрязнённые данные, любая подвыражение может быть признано загрязнённым, даже если значение подвыражения само по себе не затрагивается загрязнёнными данными.

Поскольку загрязнение ассоциируется с каждым скалярным значением, некоторые элементы массива или словаря могут быть загрязнены, а другие — нет. Ключи словаря никогда не загрязнены.

Например:

    $arg = shift;		# $arg is tainted
    $hid = $arg . 'bar';	# $hid is also tainted
    $line = <>;			# Tainted
    $line = <STDIN>;		# Also tainted
    open FOO, "/home/me/bar" or die $!;
    $line = <FOO>;		# Still tainted
    $path = $ENV{'PATH'};	# Tainted, but see below
    $data = 'abc';		# Not tainted

    system "echo $arg";		# Insecure
    system "/bin/echo", $arg;	# Considered insecure
				# (Perl doesn't know about /bin/echo)
    system "echo $hid";		# Insecure
    system "echo $data";	# Insecure until PATH set

    $path = $ENV{'PATH'};	# $path now tainted

    $ENV{'PATH'} = '/bin:/usr/bin';
    delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};

    $path = $ENV{'PATH'};	# $path now NOT tainted
    system "echo $data";	# Is secure now!

    open(FOO, "< $arg");	# OK - read-only file
    open(FOO, "> $arg"); 	# Not OK - trying to write

    open(FOO,"echo $arg|");	# Not OK
    open(FOO,"-|")
	or exec 'echo', $arg;	# Also not OK

    $shout = `echo $arg`;	# Insecure, $shout now tainted

    unlink $data, $arg;		# Insecure
    umask $arg;			# Insecure

    exec "echo $arg";		# Insecure
    exec "echo", $arg;		# Insecure
    exec "sh", '-c', $arg;	# Very insecure!

    @files = <*.c>;		# insecure (uses readdir() or similar)
    @files = glob('*.c');	# insecure (uses readdir() or similar)

    # In either case, the results of glob are tainted, since the list of
    # filenames comes from outside of the program.

    $bad = ($arg, 23);		# $bad will be tainted
    $arg, `true`;		# Insecure (although it isn't really)

Если вы попытаетесь сделать что-то небезопасное, вы получите сообщение об ошибке, например, «Небезопасная зависимость» или «Небезопасный $ENV{PATH}».

Исключением из принципа «одно загрязнённое значение загрязняет всё выражение» является тернарный условный оператор ?:. Поскольку код с тернарным условным оператором

$result = $tainted_value ? "Untainted" : "Also untainted";

фактически эквивалентен

if ( $tainted_value ) {
    $result = "Untainted";
} else {
    $result = "Also untainted";
}

нет смысла, чтобы $result было загрязнённым.

Отмывание и обнаружение загрязнённых данных

Чтобы проверить, содержит ли переменная загрязнённые данные, и использование каких данных может вызвать сообщение «Небезопасная зависимость», вы можете использовать функцию tainted() модуля Scalar::Util, доступного в вашем ближайшем зеркале CPAN и включённого в Perl начиная с версии 5.8.0. Или вы можете использовать функцию is_tainted().

sub is_tainted {
    local $@;   # Don't pollute caller's value.
    return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
}

Эта функция использует тот факт, что наличие загрязнённых данных где-либо в выражении делает всё выражение загрязнённым. Было бы неэффективно, чтобы каждый оператор проверял каждое своё аргумент на загрязнение. Вместо этого используется немного более эффективный и консервативный подход: если в рамках одного выражения был обращение к какому-либо загрязнённому значению, всё выражение считается загрязнённым.

Но проверка на загрязнённость даёт вам лишь определённые границы. Иногда вы должны просто очистить загрязнение данных. Значения могут быть очищены, используя их как ключи в словаре; в противном случае единственный способ обойти механизм проверки на загрязнение — это ссылка на подстроки из совпадения регулярного выражения. Perl предполагает, что если вы ссылаетесь на подстроку, используя $1, $2 и т. д. в ненапрягающем шаблоне, то вы знали, что делаете, когда писали этот шаблон. Это означает применение некоторого размышления — не очищайте слепо все данные, иначе вы нарушите весь механизм. Лучше убедиться, что переменная содержит только хорошие символы (в определённом смысле «хорошие»), а не проверять наличие плохих символов. Это связано с тем, что очень легко пропустить плохие символы, о которых вы никогда не думали.

Вот тест, чтобы убедиться, что данные содержат только символы «слова» (буквы, цифры и нижние подчёркивания), дефис, символ «@» или точку.

    if ($data =~ /^([-\@\w.]+)$/) {
	$data = $1; 			# $data now untainted
    } else {
	die "Bad data in '$data'"; 	# log this somewhere
    }

Это довольно безопасно, потому что /\w+/ обычно не соответствует метасимволам оболочки, а точка, дефис или символ «@» не имеют специального значения для оболочки. Теоретически использование /.+/ было бы небезопасным, потому что оно пропускает всё, но Perl не проверяет это. Урок заключается в том, что при очистке данных вы должны быть очень осторожны с шаблонами. Очистка данных с помощью регулярных выражений является единственным механизмом для очистки загрязнённых данных, если вы не используете стратегию, описанную ниже, для создания дочернего процесса с меньшими привилегиями.

В примере $data не очищается, если use locale активно, поскольку символы, соответствующие \w, определяются локалью. Perl считает, что определения локали небезопасны, потому что они содержат данные извне программы. Если вы пишете программу, учитывающую локаль, и хотите очистить данные с помощью регулярного выражения, содержащего \w, поместите no locale перед выражением в том же блоке. См. "БЕЗОПАСНОСТЬ" в perllocale для дополнительной информации и примеров.

Переключатели в строке "#!"

Когда вы делаете скрипт исполняемым, чтобы сделать его пригодным для использования в качестве команды, система передаёт переключатели perl из строки #! скрипта. Perl проверяет, что все переключатели командной строки, переданные скрипту setuid (или setgid), фактически соответствуют установленным в строке #! . Некоторые Unix-подобные среды накладывают ограничение на использование одного переключателя в строке #!, поэтому вам может потребоваться использовать что-то вроде -wU вместо -w -U в таких системах. (Эта проблема должна возникать только в Unix-подобных средах, поддерживающих #! и скрипты setuid или setgid.)

Режим проверки на загрязнение и @INC

+Когда режим проверки на загрязнение (-T) активен, переменные среды +PERL5LIB, PERLLIB, и PERL_USE_UNSAFE_INC игнорируются Perl. Вы всё ещё можете изменить @INC извне программы, используя опцию командной строки -I, как описано в perlrun. Эти две переменные среды игнорируются, потому что они скрыты, и пользователь, запускающий программу, может не знать, что они установлены, тогда как опция -I чётко видна и поэтому разрешена.

Другой способ изменить @INC без изменения программы — использование прагмы lib, например:

perl -Mlib=/foo program

Преимущество использования -Mlib=/foo по сравнению с -I/foo, заключается в том, что первое автоматически удалит все дублирующие каталоги, а второе — нет.

Обратите внимание, что если загрязнённая строка добавлена в @INC, будет сообщено об ошибке:

Insecure dependency in require while running with -T switch

В версиях Perl до 5.26 активация режима проверки на загрязнение также удаляет текущий каталог (".") из значения по умолчанию для @INC. Начиная с версии 5.26, текущий каталог по умолчанию не включается в @INC.

Настройка пути

Для сообщений «Небезопасный $ENV{PATH}» вам необходимо установить $ENV{'PATH'} на известное значение, и каждый каталог в пути должен быть абсолютным и недоступным для записи другими пользователями, кроме его владельца и группы. Вас может удивить получение этого сообщения даже в том случае, если путь к вашему исполняемому файлу полностью квалифицирован. Это не генерируется потому, что вы не указали полный путь к программе; вместо этого это генерируется потому, что вы никогда не задавали переменную среды PATH или не задавали её безопасным значением. Так как Perl не может гарантировать, что исполняемый файл не попытается выполнить какую-либо другую программу, зависящую от вашей переменной среды PATH, он убеждается, что вы задали PATH.

Переменная PATH — не единственная переменная окружения, которая может вызвать проблемы. Поскольку некоторые оболочки могут использовать переменные IFS, CDPATH, ENV и BASH_ENV, Perl проверяет, что они пусты или не загрязнены при запуске дочерних процессов. Возможно, вам потребуется добавить что-то подобное в свои скрипты проверки сета и загрязнения.

delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};   # Make %ENV safer

Возможны проблемы и с другими операциями, которым неважно, используют ли они загрязнённые значения. Делайте осознанный выбор при использовании тестов файлов с именами файлов, предоставленными пользователем. Если это возможно, выполняйте открытие и другие операции после надлежащей отмены специальных привилегий пользователя (или группы!). Perl не запрещает открытие загрязнённых файлов для чтения, поэтому будьте внимательны, что вы выводите на печать. Механизм маркировки предназначен для предотвращения глупых ошибок, а не для устранения необходимости в размышлениях.

Perl не вызывает оболочку для расширения шаблонов, когда вы передаёте system и exec явные списки параметров вместо строк с возможными шаблонами оболочки. К сожалению, функции open, glob и обратных кавычек не предоставляют альтернативной конвенции вызова, поэтому потребуется больше хитростей.

Perl предоставляет достаточно безопасный способ открыть файл или канал из программы с установленным идентификатором пользователя или группы: просто создайте дочерний процесс с уменьшенными привилегиями, который выполнит грязную работу за вас. Сначала создайте дочерний процесс с помощью специального синтаксиса open, который соединяет родительский и дочерний процессы каналом. Теперь дочерний процесс сбросит свой набор идентификаторов и любые другие атрибуты процесса, такие как переменные окружения, маски, текущие рабочие каталоги, обратно к исходным или известным безопасным значениям. Затем дочерний процесс, который больше не имеет никаких специальных разрешений, выполняет open или другую системную вызов. Наконец, дочерний процесс передаёт данные, к которым он получил доступ, родительскому процессу. Поскольку файл или канал были открыты в дочернем процессе при выполнении с меньшими привилегиями, чем у родительского, он не склонен выполнять действия, которые он не должен.

Вот способ безопасного использования обратных кавычек. Обратите внимание, что exec не вызывается со строкой, которую оболочка может расширить. Это, пожалуй, лучший способ вызова чего-либо, что может быть подвергнуто экранированию оболочки: просто никогда не вызывайте оболочку вообще.

        use English;
        die "Can't fork: $!" unless defined($pid = open(KID, "-|"));
        if ($pid) {           # parent
            while (<KID>) {
                # do something
            }
            close KID;
        } else {
            my @temp     = ($EUID, $EGID);
            my $orig_uid = $UID;
            my $orig_gid = $GID;
            $EUID = $UID;
            $EGID = $GID;
            # Drop privileges
            $UID  = $orig_uid;
            $GID  = $orig_gid;
            # Make sure privs are really gone
            ($EUID, $EGID) = @temp;
            die "Can't drop privileges"
                unless $UID == $EUID  && $GID eq $EGID;
            $ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH.
	    # Consider sanitizing the environment even more.
            exec 'myprog', 'arg1', 'arg2'
                or die "can't exec myprog: $!";
        }

Аналогичная стратегия сработает для расширения шаблонов с помощью glob, хотя вы можете использовать readdir вместо этого.

Проверка загрязнения наиболее полезна, когда вы доверяете себе, что не написали программу, которая предаст всё нажитое, но не обязательно доверяете тем, кто в конечном итоге будет её использовать, что они не попытаются ввести её в заблуждение, заставив сделать что-то плохое. Такая проверка безопасности полезна для программ с установленным идентификатором пользователя и для программ, запускаемых от имени другого пользователя, например, CGI-программ.

Однако это сильно отличается от того, чтобы не доверять даже автору кода, что он не попытается совершить злодейское действие. Такое доверие требуется, когда кто-то даёт вам программу, которую вы никогда раньше не видели, и говорит: «Вот, запустите её». Для такой безопасности вы можете ознакомиться с модулем Safe, включённым в стандартную дистрибуцию Perl. Этот модуль позволяет программисту создавать специальные отсеки, в которых все системные операции отслеживаются, а доступ к именованным пространствам тщательно контролируется. Safe не следует считать полностью защищённым: он не предотвратит создание бесконечных циклов, выделение гигабайтов памяти или даже использование ошибок perl для создания сбоя интерпретатора хоста или непредсказуемого поведения. В любом случае, его следует избегать полностью, если безопасность для вас действительно важна.

Состояние гонки shebang

Помимо очевидных проблем, возникающих из-за предоставления специальных привилегий таким гибким системам, как скрипты, на многих версиях Unix скрипты с установленным идентификатором пользователя изначально небезопасны. Проблема заключается в состоянии гонки в ядре. Между тем, как ядро открывает файл, чтобы определить, какой интерпретатор запустить, и тем, как интерпретатор (теперь с установленным идентификатором пользователя) возвращается и повторно открывает файл для интерпретации, файл может быть изменён, особенно если на вашей системе есть символические ссылки.

Некоторые Unixes, особенно более новые, лишены этой встроенной ошибки безопасности. На таких системах ядро передаёт имя скрипта с установленным идентификатором пользователя для открытия интерпретатору, а не используя путь, который можно изменить, а вместо этого передаёт /dev/fd/3. Это специальный файл, уже открытый в скрипте, поэтому злонамеренные скрипты не могут использовать состояние гонки. На этих системах Perl должен быть скомпилирован с -DSETUID_SCRIPTS_ARE_SECURE_NOW. Программа Configure, которая собирает Perl, пытается выяснить это сама, поэтому вам никогда не придётся указывать это самостоятельно. Большинство современных релизов SysVr4 и BSD 4.4 используют этот подход для предотвращения состояния гонки в ядре.

Если у вас нет безопасной версии скриптов с установленным идентификатором пользователя, всё ещё не всё потеряно. Иногда эту «функцию» ядра можно отключить, чтобы ядро либо не запускало скрипты с установленным идентификатором пользователя, либо не запускало их вообще. В любом случае это предотвращает возможность злоупотребления состоянием гонки, но не помогает фактически запустить скрипты с установленным идентификатором пользователя.

Если функция ядра для скриптов с установленным идентификатором пользователя не отключена, любой такой скрипт представляет собой уязвимость, которую можно эксплуатировать. Perl не может избежать эксплуатации, но укажет уязвимые скрипты, где это возможно. Если Perl обнаруживает, что он применяется к скрипту с установленным идентификатором пользователя, то он громко сообщит, что ваш скрипт с установленным идентификатором пользователя небезопасен и не запустит его. Когда Perl жалуется, вам нужно удалить бит установленного идентификатора пользователя из скрипта, чтобы устранить уязвимость. Отказаться от запуска скрипта само по себе не устраняет уязвимость; это просто способ Perl побудить вас сделать это.

Для фактического запуска скрипта с установленным идентификатором пользователя, если у вас нет безопасной версии скриптов с установленным идентификатором пользователя, вам понадобится обертка на C вокруг скрипта. Обёртка на C — это просто скомпилированная программа, которая ничего не делает, кроме вызова вашей программы Perl. Скомпилированные программы не подвержены ошибке ядра, которая затрагивает скрипты с установленным идентификатором пользователя. Вот простая обёртка, написанная на C:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#define REAL_PATH "/path/to/script"

int main(int argc, char **argv)
{
    execv(REAL_PATH, argv);
    fprintf(stderr, "%s: %s: %s\n",
                    argv[0], REAL_PATH, strerror(errno));
    return 127;
}

Скомпилируйте эту обёртку в исполняемый файл, а затем предоставьте ей, а не вашему скрипту, установленный идентификатор пользователя или группы. Обратите внимание, что эта обёртка ничего не делает для очистки среды выполнения, кроме обеспечения использования безопасного пути к скрипту. Она только предотвращает состояние гонки shebang. Она полагается на собственные возможности Perl и на то, что сам скрипт осторожен, чтобы сделать его достаточно безопасным для запуска скрипта с установленным идентификатором пользователя.

Защита ваших программ

Существует множество способов скрыть исходный код ваших программ Perl с различными уровнями «безопасности».

Однако прежде всего вы не можете лишить разрешения на чтение, потому что исходный код должен быть доступен для чтения, чтобы его можно было скомпилировать и интерпретировать. (Это не означает, что исходный код CGI-скрипта доступен для чтения людям в Интернете.) Поэтому вы должны оставить разрешения на уровне 0755. Это позволяет пользователям вашей локальной системы видеть только ваш исходный код.

Некоторые люди ошибочно считают это проблемой безопасности. Если ваша программа делает небезопасные вещи и полагается на то, что люди не знают, как эксплуатировать эти недостатки, она не является безопасной. Часто возможно определить небезопасные действия и воспользоваться ими без просмотра исходного кода. Безопасность через неявность, то есть скрытие ошибок вместо их исправления, — это весьма ограниченная безопасность.

Вы можете попробовать использовать шифрование с помощью фильтров исходного кода (Filter::* из CPAN или Filter::Util::Call и Filter::Simple с Perl 5.8). Но хакеры могут его расшифровать. Вы можете попробовать использовать компилятор и интерпретатор байтового кода, описанные ниже, но хакеры могут его декомпилировать. Вы можете попробовать использовать компилятор нативного кода, описанный ниже, но хакеры могут его дизассемблировать. Это создаёт различные трудности для тех, кто хочет получить доступ к вашему коду, но ничего не может окончательно скрыть его (это верно для любого языка, а не только Perl).

Если вы обеспокоены использованием вашего кода для получения прибыли, то единственное, что может обеспечить вам юридическую безопасность, — это ограничительную лицензию. Лицензируйте своё программное обеспечение и снабдите его угрожающими заявлениями, такими как «Это не опубликованное конфиденциальное программное обеспечение XYZ Corp. Ваш доступ к нему не даёт вам разрешения использовать его blah blah blah». Вам следует проконсультироваться с юристом, чтобы убедиться, что формулировка вашей лицензии будет действенной в суде.

Unicode

Unicode — новая и сложная технология, и можно легко упустить из виду определённые уязвимости. См. perluniintro для обзора и perlunicode для деталей, а также "Security Implications of Unicode" в perlunicode для конкретных последствий для безопасности.

Атаки на алгоритмическую сложность

Некоторые внутренние алгоритмы, используемые в реализации Perl, могут подвергаться атакам за счёт тщательного выбора входных данных, чтобы потребить большое количество времени или места или обоих одновременно. Это может привести к атакам типа «отказ в обслуживании» (DoS).

  • Алгоритм хеширования — Алгоритмы хеширования, подобные используемому в Perl, известны своей уязвимостью к атакам на столкновения в своей функции хеширования. Такие атаки включают построение набора ключей, которые сталкиваются в одном и том же ведре, что приводит к неэффективному поведению. Такие атаки часто зависят от обнаружения начального значения функции хеширования, используемой для сопоставления ключей с ведрами. Это значение затем используется для перебора ключей, которые могут быть использованы для атаки типа отказа в обслуживании. В Perl 5.8.1 были внесены изменения для повышения устойчивости Perl к таким атакам, а затем, в Perl 5.18.0, эти функции были улучшены и добавлены дополнительные средства защиты.

    На момент написания этой статьи Perl 5.18.0 считается хорошо защищенным от атак на алгоритмическую сложность его реализации хеширования. Это в значительной степени обусловлено следующими мерами по смягчению атак:

    Случайная инициализация начального значения хеширования

    Для того, чтобы невозможно было определить, какое начальное значение использовать для генерации набора ключей атаки, это начальное значение случайным образом инициализируется при запуске процесса. Это можно переопределить, используя переменную окружения PERL_HASH_SEED, см. "PERL_HASH_SEED" в perlrun. Эта переменная окружения управляет тем, как элементы фактически хранятся, а не тем, как они представлены с помощью keys, values и each.

    Случайная выборка элементов хеша

    Независимо от того, какое начальное значение используется в функции хеширования, keys, values, и each возвращают элементы в случайном порядке для каждого хеша. Изменение хеша путем вставки изменит порядок итерации этого хеша. Это поведение можно переопределить, используя hash_traversal_mask() из Hash::Util или используя переменную окружения PERL_PERTURB_KEYS, см. "PERL_PERTURB_KEYS" в perlrun. Обратите внимание, что эта функция управляет «видимым» порядком ключей, а не фактическим порядком их хранения.

    Перемешивание порядка ведер

    Когда элементы сталкиваются в данном ведре хеша, порядок их хранения в цепочке больше не является предсказуемым в Perl 5.18. Это направлено на то, чтобы затруднить наблюдение за столкновением. Это поведение можно переопределить, используя переменную окружения PERL_PERTURB_KEYS, см. "PERL_PERTURB_KEYS" в perlrun.

    Новая функция хеширования по умолчанию

    Функция хеширования по умолчанию была изменена с целью затруднения определения начального значения хеша.

    Альтернативные функции хеширования

    Исходный код включает несколько алгоритмов хеширования на выбор. Хотя мы считаем, что стандартный хеш Perl устойчив к атакам, мы включили функцию хеширования Siphash в качестве варианта по умолчанию. На момент выпуска Perl 5.18.0 Siphash считается криптографически стойкой функцией. Это не значение по умолчанию, так как оно значительно медленнее, чем стандартный хеш.

    Без компиляции специальной версии Perl невозможно получить точно такое же поведение, как в версиях до Perl 5.18.0. Наиболее близким можно считать установку PERL_PERTURB_KEYS в 0 и установку PERL_HASH_SEED в известное значение. Мы не рекомендуем эти настройки для использования в производстве из-за упомянутых выше соображений безопасности.

    Perl никогда не гарантировал никакого порядка ключей хеша, и этот порядок уже несколько раз менялся в течение жизненного цикла Perl 5. Кроме того, порядок ключей хеша всегда и продолжает зависеть от порядка вставки и истории изменений, внесенных в хеш за его время существования.

    Также обратите внимание, что хотя порядок элементов хеша может быть случайным, этот «псевдопорядок» не следует использовать для задач, таких как случайное перемешивание списка (используйте List::Util::shuffle() для этого, см. List::Util, стандартный модуль ядра с Perl 5.8.0; или модуль CPAN Algorithm::Numerical::Shuffle), или для генерации перестановок (используйте, например, модули CPAN Algorithm::Permute или Algorithm::FastPermute), или для любых криптографических приложений.

    Связанные хеши могут иметь свой собственный порядок и алгоритмические атаки.

  • Регулярные выражения — Двигатель регулярных выражений Perl — это так называемый NFA (недетерминированный конечный автомат), что, помимо прочего, означает, что он может довольно легко потреблять большое количество времени и памяти, если регулярное выражение может совпадать несколькими способами. Тщательное составление регулярных выражений может помочь, но довольно часто в этом нет особого смысла (книга «Mastering Regular Expressions» — обязательное чтение, см. perlfaq2). Нехватка памяти проявляется в том, что Perl выходит из строя.

  • Сортировка — алгоритм быстрой сортировки, используемый в Perl до версии 5.8.0 для реализации функции sort(), был очень уязвим для обмана, что приводило к большому потреблению времени. Начиная с Perl 5.8.0, по умолчанию используется другой алгоритм сортировки — слияние. Сортировка слиянием не может выйти из строя при любом вводе.

Дополнительную информацию см. в https://www.usenix.org/legacy/events/sec03/tech/full_papers/crosby/crosby.pdf и в любом учебнике по информатике по алгоритмической сложности.

Использование Sudo

Популярный инструмент sudo предоставляет контролируемый способ для пользователей запускать программы от имени других пользователей. Он до некоторой степени очищает среду выполнения и предотвратит проблему «гонки shebang». Если у вас нет безопасной версии скриптов с установкой идентификаторов, то sudo может быть более удобным способом запуска скрипта от имени другого пользователя, чем написание обертки на C.

Однако sudo устанавливает реальный идентификатор пользователя или группы в идентификатор целевого пользователя, а не только эффективный идентификатор, как это делают биты set-id. В результате Perl не может обнаружить, что он работает под sudo, и поэтому не будет автоматически принимать свои собственные меры безопасности, такие как включение режима taint. Там, где конфигурация sudo определяет, какие именно команды могут быть выполнены, разрешенная команда может включать опцию -T для perl, чтобы включить режим taint.

В общем случае необходимо оценить пригодность скрипта для запуска под sudo, особенно с учетом такой среды выполнения. Это ни необходимо, ни достаточно для того, чтобы тот же скрипт был пригоден для запуска в традиционной схеме set-id, хотя многие проблемы перекрываются.

См. также

"ENVIRONMENT" в perlrun для описания очистки переменных окружения.

© 1993–2023 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.38.0/perlsec

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API