perlsec
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- КОНТАКТНАЯ ИНФОРМАЦИЯ О НАРУШЕНИИ БЕЗОПАСНОСТИ
- МЕХАНИЗМЫ И ВОПРОСЫ БЕЗОПАСНОСТИ
- СМОТРИТЕ ТАКЖЕ
НАЗВАНИЕ
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) Если вы попытаетесь сделать что-то небезопасное, вы получите ошибку с сообщением, похожим на «Небезопасная зависимость» или «Небезопасная переменная окружения 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 предоставляет достаточно безопасный способ открытия файла или канала связи из программы с setuid или setgid: просто создайте дочерний процесс с уменьшенными привилегиями, который выполнит грязную работу за вас. Во-первых, разделите дочерний процесс с помощью специального open синтаксиса, который соединяет родительский и дочерний процессы через канал. Теперь дочерний процесс сбрасывает свой набор идентификаторов и любые другие атрибуты процесса, такие как переменные окружения, umask, текущие рабочие каталоги, до оригинальных или известных безопасных значений. Затем дочерний процесс, который больше не имеет особых разрешений, выполняет open или другие системные вызовы. Наконец, дочерний процесс передаёт данные, к которым он получил доступ, обратно родительскому процессу. Поскольку файл или канал были открыты в дочернем процессе, работающем с меньшими привилегиями, чем родительский, он не склонен к обману и выполнению нежелательных действий.
Вот способ выполнения backticks безопасно. Обратите внимание, как 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 вместо этого.
Проверка на заражённость наиболее полезна, когда вы доверяете себе, но не обязательно доверяете пользователям, которые будут использовать программу, чтобы не пытаться заставить её совершить что-то плохое. Это тот вид проверки безопасности, который полезен для программ set-id и программ, запущенных от имени другого пользователя, например, CGI-программ.
Однако это совершенно отличается от того, чтобы не доверять даже автору кода в том, что он не попытается сделать что-то злонамеренное. Такое доверие необходимо, когда кто-то даёт вам программу, которую вы никогда раньше не видели, и говорит: «Вот, запустите это». Для такого рода безопасности вы можете изучить модуль Safe, включённый в стандартную поставку Perl. Этот модуль позволяет программисту создавать специальные отсеки, в которых все системные операции перехватываются, а доступ к именам пространств тщательно контролируется. Не следует считать Safe абсолютно надёжным: он не предотвратит создание бесконечных циклов, выделение гигабайтов памяти или даже злоупотребление ошибками perl для того, чтобы заставить интерпретатор-хост аварийно завершиться или вести себя непредсказуемо. В любом случае его лучше избегать, если вы действительно обеспокоены безопасностью.
Уязвимость гонки shebang
Помимо очевидных проблем, связанных с предоставлением особых привилегий таким гибким системам, как скрипты, на многих версиях Unix скрипты set-id изначально небезопасны. Проблема заключается в гонке в ядре. В период между моментом, когда ядро открывает файл, чтобы определить, какой интерпретатор запустить, и моментом, когда (теперь уже set-id) интерпретатор поворачивается и снова открывает файл для интерпретации, файл, о котором идёт речь, может измениться, особенно если на вашей системе есть символические ссылки.
Некоторые версии Unix, особенно более новые, свободны от этой встроенной уязвимости безопасности. На таких системах, когда ядро передаёт имя скрипта set-id для открытия интерпретатору, вместо использования пути, подверженного вмешательству, оно вместо этого передаёт /dev/fd/3. Это специальный файл, уже открытый в скрипте, так что нет никакой гонки, которую могут использовать зловредные скрипты. На этих системах Perl следует компилировать с -DSETUID_SCRIPTS_ARE_SECURE_NOW. Программа Configure, которая собирает Perl, пытается выяснить это самостоятельно, поэтому вам никогда не придётся указывать это самостоятельно. Большинство современных релизов SysVr4 и BSD 4.4 используют этот подход для предотвращения гонки в ядре.
Если у вас нет безопасной версии скриптов set-id, всё ещё не всё потеряно. Иногда эту «функцию» ядра можно отключить, так что ядро либо не запускает скрипты set-id с set-id, либо не запускает их вообще. В любом случае это предотвращает возможность использования уязвимости гонки, но не помогает в фактическом запуске скриптов set-id.
Если функция скриптов set-id ядра не отключена, то любой скрипт set-id представляет собой эксплуатируемую уязвимость. Perl не может избежать эксплуатируемости, но укажет уязвимые скрипты, где это возможно. Если Perl обнаруживает, что он применяется к скрипту set-id, он громко пожалуется на то, что ваш скрипт set-id небезопасен, и не запустит его. Когда Perl жалуется, вам нужно удалить бит set-id из скрипта, чтобы устранить уязвимость. Отказание от запуска скрипта само по себе не закрывает уязвимость; это просто способ Perl побудить вас сделать это.
Чтобы фактически запустить скрипт set-id, если у вас нет безопасной версии скриптов set-id, вам потребуется поместить C-оболочку вокруг скрипта. C-оболочка — это просто скомпилированная программа, которая ничего не делает, кроме как вызывает вашу Perl-программу. Скомпилированные программы не подвержены проблеме ядра, которая затрагивает скрипты set-id. Вот простая оболочка, написанная на 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;
} Скомпилируйте эту оболочку в исполняемый двоичный файл, а затем сделайте ее, а не ваш скрипт setuid или setgid. Обратите внимание, что эта оболочка ничего не делает для очистки среды выполнения, кроме как гарантирует использование безопасного пути к скрипту. Она только избегает уязвимости гонки shebang. Она полагается на собственные функции Perl и на то, что сам скрипт осторожен, чтобы сделать его достаточно безопасным для запуска скрипта set-id.
Защита ваших программ
Существует ряд способов скрыть исходный код ваших Perl-программ с различными уровнями «безопасности».
Однако, прежде всего, вы не можете отобрать разрешение на чтение, потому что исходный код должен быть доступен для чтения, чтобы его можно было скомпилировать и интерпретировать. (Это не означает, что исходный код скрипта CGI доступен для просмотра пользователям в веб-сети.) Поэтому вам нужно оставить разрешения на уровне 0755, что удобно для общества. Это позволяет людям в вашей локальной системе видеть только ваш исходный код.
Некоторые люди ошибочно считают это проблемой безопасности. Если ваша программа делает небезопасные вещи и полагается на то, что люди не знают, как использовать эти уязвимости, она не является безопасной. Часто можно определить небезопасные вещи и использовать их, не просматривая исходный код. Защита через сокрытие, метод сокрытия ошибок вместо их исправления, — это ненадёжная защита.
Вы можете попробовать использовать шифрование с помощью фильтров исходного кода (Filter::* из CPAN или Filter::Util::Call и Filter::Simple с Perl 5.8). Но взломщики могут быть в состоянии его расшифровать. Вы можете попробовать использовать компилятор и интерпретатор байткода, описанный ниже, но взломщики могут быть в состоянии его декомпилировать. Вы можете попробовать использовать компилятор native-code, описанный ниже, но взломщики могут быть в состоянии его дизассемблировать. Эти методы создают различную степень сложности для тех, кто хочет получить доступ к вашему коду, но ни один из них не может окончательно скрыть его (это относится к любому языку программирования, а не только к Perl).
Если вы обеспокоены получением прибыли от вашего кода, то единственное, что может обеспечить вам юридическую безопасность, — это ограничительная лицензия. Лицензируйте свой программный продукт и заполните его угрожающими заявлениями, такими как «Это непубличная собственность XYZ Corp. Ваш доступ к нему не даёт вам разрешения использовать его ... и т.д.». Для получения консультации по формулировке вашей лицензии обратитесь к юристу.
Unicode
Unicode — это новая и сложная технология, и можно легко упустить из виду определённые уязвимости в области безопасности. См. perluniintro для обзора, perlunicode для деталей и "Security Implications of Unicode" in 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; или модуль CPANAlgorithm::Numerical::Shuffle) или для генерации перестановок (используйте, например, модули CPANAlgorithm::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–2021 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.36.0/perlsec