Безпечне програмування на perl

Як уникнути передачі призначених для користувача змінних оболонці ОС при виклику exec () і system ()?

У Perl ви можете запускати зовнішні програми різними шляхами. Ви можете перехоплювати висновок зовнішніх програм, використовуючи зворотні лапки:

Ви можете відкривати "тунель" (pipe) до програми:

open (SORT, "| / usr / bin / sort | / usr / bin / uniq");

Ви можете запускати зовнішні програми і чекати закінчення їх виконання через system ():

system "/ usr / bin / sort

або ви можете запускати зовнішні програми без повернення управління за допомогою exec ():

exec "/ usr / bin / sort

Всі ці вирази є небезпечними якщо використовують дані, введені користувачем, які можуть містити метасимволи. Для system () і exec () існує синтаксична можливість, що дозволяє запускати зовнішні програми безпосередньо, без звернення до оболонки ОС. Якщо ви передаєте зовнішньої програмі аргументи, що представляють собою не рядок, а список, то Perl не буде використовувати оболонку, і метасимволи не викличуть небажаних побічних ефектів. наприклад:

Ви можете використовувати цю особливість для того, щоб відкрити тунель, не звертаючись до оболонки ОС. Викликаючи open в магічній послідовності символів | -, ви запускаєте копію Perl і відкриваєте тунель (pipe) до цієї копії. Дочірня копія Perl потім негайно запускати зовнішню програму, використовуючи список аргументів для exec ().

open (SORT, "| -") || exec "/ usr / bin / sort", $ uservariable;

while $ line (@lines)

print SORT $ line, "\ n";

Для читання з тунелю без звернення до оболонки можна використовувати схожий спосіб, з послідовністю - |:

open (GREP, "- |") || exec "/ usr / bin / grep", $ userpattern, $ filename;

print "match: $ _";

Це ті форми open (), які необхідно завжди використовувати у випадках, коли в іншій ситуації ви використовували б перенаправлення open (piped open).

Ще більш хитра можливість дозволяє вам запускати зовнішні програми і обманювати їх щодо їх власної назви. Це корисно при використанні програм, дії яких залежать від того, з використанням якого імені вони запущені.

system $ настоящее_імя "ложное_імя", "аргумент1", "аргумент2"

system $ shell "-sh", "- norc"

Цей приклад запускає sh - оболонку операційної системи - з ім'ям "-sh", який змушує її діяти інтерактивно. Заметте, що справжнє ім'я програми повинно зберігатися у вигляді змінної, і що між ім'ям змінної і початком списку аргументів немає коми.

Можна записати цю команду більш компактно:

Що таке "перевірки заразність" (taint checks) в Perl? Як їх включити?

Як ми бачили, одна з найбільш часто зустрічаються проблем з безпекою при програмуванні CGI - передача оболонці ОС для користувача змінних без їх перевірки. Perl пропонує механізм перевірки "заразність", який не дозволяє цього робити. Будь-яка змінна, яка проініціювати даними за межами програми (включаючи дані з середовища, стандартного введення і командного рядка) розглядається як "заразна", і не може бути більше використана за межами програми. Зараза може поширюватися. Якщо ви використовуєте заражену змінну для присвоєння значення іншої змінної, друга змінна також виявляється заражена. Заражені змінні не можуть бути використані для виклику eval (), system (), exec () або piped open (). Якщо ви спробуєте це зробити, Perl припиняє роботу і виводить попередження. Perl також відмовиться працювати, якщо ви спробуєте викликати зовнішню програму, не встановивши явно значення змінної PATH.

У версії 4 мови Perl перевірка включається при використанні спеціальної версії інтерпретатора, яка називається "taintperl":

У версії 5 - використовуйте прапор -T при запуску інтерпретатора:

Нижче описано як "знезаражувати" (untaint) змінні.

OK, я включив перевірку заразність, як ви рекомендували. Тепер мій скрипт припиняє роботу з повідомленням "Insecure $ ENV at line XX" при кожному запуску!

Навіть якщо ви не довіряєте змінної PATH при запуску зовнішніх програм, існує можливість того, що це робить зовнішня програма. Тому слід завжди включати такий рядок на початку вашого скрипта, якщо ви використовуєте taint checks:

Відредагуйте її так, щоб перерахувати директорії, в яких ви хочете шукати. Думка про вклюяеніі поточного директорія ( ".") До складу змінної PATH є поганою ідеєю.

Як "знезаразити (untaint) змінну?

Я видаляю метасимволи із змінної, але Perl продовжує думати, що вона заражена!

Дивись вище відповідь на це питання. Єдиний спосіб знезаразити змінну - застосувати пошук по масці.

Чи справді небезпечна операція пошуку $ foo =

Часто завдання скрипта CGI на Perl полягає в отриманні від користувача списку ключових слів і використання їх в операціях пошуку по масці для знаходження співпадаючих імен файлів (або чого - небудь в цьому роді). Само по собі це не небезпечно. Небезпечна оптимізація, яку деякі програми Perl використовують для прискорення пошуку. При використанні змінної в операції пошуку, вираз компілюється всякий раз при виконанні операції. Для уникнення перекомпілірованія, що займає час, можна використовувати спеціальний прапор - o, що призведе до того, що вираз буде відкомпілювати тільки один раз:

Тепер, однак, Perl буде ігнорувати будь-які зміни в змінної, що призведе до неправильної роботи циклів такого роду:

foreach $ user_pattern (@user_patterns)

print if m / $ user_pattern / o;

Для обходу цієї проблеми програмісти, які пишуть на Perl, часто використовують такий трюк:

foreach $ user_pattern (@user_patterns)

print if m / \ Q $ user_pattern \ E / o;

Мій скрипт CGI вимагає великі привілеї, ніж він отримує як користувач nobody. Як мені змінити ідентифікатор користувача?

Ви можете змусити скрипт виконуватися з правами його власника шляхом установки біта s:

Ви можете надати йому права групи, до якої належить власник, встановивши біт s в полі групи:

Однак, багато систем Unix містять лазівку, що дозволяє зламувати такі скрипти. Це стосується тільки скриптів, а не компілювати програм. У таких системах спроба запуску скрипта на Perl, для якого були виставлені s біти, призведе до появи повідомлення про помилку з боку самого Perl.

На таких системах ви маєте дві можливості:

Можна виправити ядро ​​так, щоб заборонити установку цих бітів для файлів скриптів. Perl проте буде правильно визначати ці біти і встановлювати ідентифікатор користувача. Детальну інформацію про це можна знайти в Perl faq:

Ви можете помістити скрипт в оболонку, напмсанную на C. Зазвичай це виглядає так:

Після компіляції програми, виставте s біти. Програма буде виконуватися з правами власника, запускати інтерпретатор Perl і виконувати скрипт, що міститься у файлі "foo.pl".

Крім того, можна запускати сам сервер з правами користувача, достатніми для виконання необхідних дій. Якщо ви використовуєте сервер CERN, то у вас є можливість запускати сервер з різними правами для різних скриптів. Див. Документацію CERN для отримання подальшої інформації.

Схожі статті