perlsec
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- КОНТАКТНАЯ ИНФОРМАЦИЯ О НАРУШЕНИЯХ БЕЗОПАСНОСТИ
- МЕХАНИЗМЫ И ВОПРОСЫ БЕЗОПАСНОСТИ
- СМОТРИТЕ ТАКЖЕ
НАЗВАНИЕ
perlsec - Безопасность Perl
ОПИСАНИЕ
Perl разработан для простоты программирования в безопасном режиме, даже при выполнении с повышенными привилегиями, например, в setuid или setgid программах. В отличие от большинства командных оболочек, которые основаны на нескольких проходах по подстановке каждой строки скрипта, Perl использует более традиционную схему оценки с меньшим количеством скрытых проблем. Кроме того, поскольку язык обладает более широким набором встроенных функций, он меньше полагается на внешние (и, возможно, ненадежные) программы для выполнения своих задач.
КОНТАКТНАЯ ИНФОРМАЦИЯ О НАРУШЕНИЯХ БЕЗОПАСНОСТИ
Если вы считаете, что обнаружили уязвимость в системе безопасности Perl, пожалуйста, отправьте подробности по электронной почте на адрес perl5-security-report@perl.org. Это создаст новый запрос в системе отслеживания задач в специальной очереди, которая первоначально не доступна для общественности. Почта также будет скопирована на закрытый неопубликованный список рассылки, включающий всех ключевых разработчиков, которые смогут помочь оценить последствия проблем, найти решение и помочь координировать выпуск исправлений для смягчения или исправления проблемы на всех платформах, где поддерживается Perl. Используйте этот адрес только для проблем с безопасностью в ядре Perl, а не для модулей, распространяемых независимо на CPAN.
При отправке начального запроса на адрес электронной почты для безопасности не добавляйте Cc другим лицам, так как если они ответят всем, ответ сгенерирует еще один новый запрос. После получения первоначального ответа с номером запроса [perl #NNNNNN] в заголовке, в последующих ответах можно добавлять Cc третьим лицам: все электронные письма на адрес perl5-security-report с номером запроса в строке темы будут добавлены в запрос; без него будет создан новый запрос.
МЕХАНИЗМЫ И ВОПРОСЫ БЕЗОПАСНОСТИ
Режим слежения за заражёнными данными
Perl автоматически включает набор специальных проверок безопасности, называемый режимом слежения за заражёнными данными (taint mode), когда он обнаруживает, что его программа выполняется с разными реальными и эффективными идентификаторами пользователя или группы. Флаг setuid в разрешениях Unix имеет код 04000, флаг setgid имеет код 02000; может быть установлен один или оба. Вы также можете включить режим слежения за заражёнными данными явно, используя командную строку -T. Этот флаг настоятельно рекомендуется для серверных программ и для любой программы, выполняющейся от имени другого пользователя, например, CGI-скрипт. После включения режима слежения за заражёнными данными, он остается включенным до конца выполнения скрипта.
В этом режиме Perl принимает особые меры предосторожности, называемые проверками заражённых данных (taint checks), для предотвращения очевидных и скрытых ловушек. Некоторые из этих проверок довольно простые, например, проверка того, что каталоги путей не могут быть записаны другими пользователями; внимательные программисты всегда использовали такие проверки. Однако другие проверки лучше всего поддерживаются самим языком, и именно эти проверки в особенности способствуют повышению безопасности программы Perl с установленным идентификатором по сравнению с соответствующей программой на C.
Вы не можете использовать данные, полученные извне вашей программы, для воздействия на что-либо вне вашей программы — по крайней мере, не случайно. Все аргументы командной строки, переменные окружения, информация о языке (см. perllocale), результаты некоторых системных вызовов (readdir(), readlink(), переменная shmread(), сообщения, возвращаемые msgrcv(), пароль, поля gcos и shell, возвращаемые вызовами getpwxxx()) и весь входной файл помечаются как «заражённые». Заражённые данные не могут использоваться напрямую или косвенно в любом командном вызове, запускающем подоболочку, ни в какой команде, изменяющей файлы, каталоги или процессы, с следующими исключениями:
-
Аргументы
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), каталог «.» удаляется из @INC, а переменные окружения PERL5LIB и PERLLIB игнорируются Perl. Вы всё ещё можете изменить @INC снаружи программы, используя опцию командной строки -I, как описано в perlrun. Две переменные окружения игнорируются, потому что они скрыты, и пользователь, выполняющий программу, может не знать, что они установлены, в то время как опция -I явно видна и поэтому разрешена.
Другой способ изменить @INC без изменения программы — использовать pragma lib, например:
perl -Mlib=/foo program Преимущества использования -Mlib=/foo по сравнению с -I/foo, заключается в том, что первое автоматически удалит все дублирующиеся каталоги, а второе — нет.
Обратите внимание, что если заражённая строка добавлена к @INC, будет сообщено следующее:
Insecure dependency in require while running with -T switch Очистка пути
Для сообщений «Небезопасные $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 скрипты с установленным идентификатором пользователя изначально небезопасны. Проблема заключается в гонке в ядре. Между моментом, когда ядро открывает файл, чтобы определить интерпретатор, который будет запущен, и моментом, когда (теперь уже с установленным идентификатором пользователя) интерпретатор возвращается и повторно открывает файл для его интерпретации, файл, о котором идет речь, может измениться, особенно если на вашей системе есть символические ссылки.
Некоторые версии Unix, особенно более новые, лишены этой внутренней проблемы безопасности. В таких системах, когда ядро передает имя скрипта с установленным идентификатором пользователя интерпретатору для открытия, а не использует путь, который может быть изменен, оно вместо этого передает /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. Ваш доступ к нему не дает вам разрешения использовать его бла-бла-бла». Вам следует проконсультироваться с юристом, чтобы убедиться, что формулировка вашей лицензии будет соблюдаться в суде.
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; или модуль CPANAlgorithm::Numerical::Shuffle), или для генерации перестановок (используйте, например, модули CPANAlgorithm::PermuteилиAlgorithm::FastPermute), или для каких-либо криптографических применений.Связанные хеши могут иметь свой собственный порядок и атаки на алгоритмическую сложность.
-
Регулярные выражения - Двигатель регулярных выражений Perl называется NFA (недетерминированный конечный автомат), что, помимо прочего, означает, что он может довольно легко потреблять большие объемы времени и памяти, если регулярное выражение может соответствовать несколькими способами. Тщательное составление регулярных выражений может помочь, но часто практически ничего нельзя сделать (книга «Овладение регулярными выражениями» является обязательным чтением, см. 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. Если у вас нет безопасной версии скриптов set-id, то sudo может быть более удобным способом запуска скрипта от имени другого пользователя, чем написание обертки на C.
Однако sudo устанавливает действительный идентификатор пользователя или группы на идентификатор целевого пользователя, а не только эффективный идентификатор, как это делают биты set-id. В результате Perl не может определить, что он работает под sudo, и поэтому не будет автоматически принимать собственные меры предосторожности, такие как включение режима taint.
Где конфигурация sudo определяет, какие команды могут быть запущены, одобренная команда может включать опцию -T для perl для включения режима taint.
В общем случае необходимо оценить применимость скрипта для запуска под sudo с учетом именно такой среды выполнения. Это не является ни необходимым, ни достаточным условием для того, чтобы тот же скрипт подходил для запуска в традиционной схеме set-id, хотя многие проблемы перекрываются.
См. также
perlrun для описания очистки переменных среды.
© 1993–2020 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.28.3/perlsec