Безопасность PHP: Что такое атака Path Traversal и как функция realpath() помогает предотвратить доступ к системным файлам через URL?

## Что такое атака Path Traversal?

Path Traversal (обход пути, или Directory Traversal) — это тип атаки на веб-приложения, при которой злоумышленник манипулирует параметрами URL или формы, чтобы получить доступ к файлам и директориям, находящимся за пределами разрешённой корневой папки веб-сервера.

Классический пример уязвимого PHP-кода:

php
$file = $_GET[‘file’];
echo file_get_contents(‘/var/www/html/files/’ . $file);

Если пользователь передаёт параметр `?file=../../etc/passwd`, итоговый путь становится `/var/www/html/files/../../etc/passwd`, что фактически разрешается в `/etc/passwd` — системный файл с данными пользователей. Таким образом атакующий может читать конфигурационные файлы, ключи SSH, файлы с паролями базы данных и другие критически важные данные.

### Техники обхода фильтров

Атакующие используют различные способы обхода наивных проверок:
— URL-кодирование: `%2e%2e%2f` вместо `../`
— Двойное кодирование: `%252e%252e%252f`
— Смешанные разделители: `../`, `..%5c`
— Нулевые байты (в старых версиях PHP): `../../etc/passwd%00.jpg`

## Как работает функция realpath()

Функция `realpath()` в PHP возвращает канонический абсолютный путь к файлу, разрешая все символические ссылки, убирая `..`, `.` и лишние слэши. Если файл не существует — возвращает `false`.

php
realpath(‘/var/www/html/files/../../etc/passwd’);
// Вернёт: /etc/passwd

### Правильная защита с realpath()

php
$baseDir = ‘/var/www/html/files/’;
$requestedFile = $_GET[‘file’];

$realBase = realpath($baseDir);
$realPath = realpath($baseDir . $requestedFile);

if ($realPath === false || strpos($realPath, $realBase) !== 0) {
http_response_code(403);
die(‘Доступ запрещён’);
}

echo file_get_contents($realPath);

Логика защиты:
1. `realpath()` разворачивает все `../` и символические ссылки в реальный путь.
2. Проверяем, что итоговый путь начинается с базовой директории.
3. Если путь выходит за пределы — отказываем в доступе.

### Дополнительные меры безопасности

— **Белый список файлов**: разрешайте только конкретные имена или расширения.
— **basename()**: используйте для извлечения только имени файла без пути.
— **Права файловой системы**: веб-сервер должен работать с минимальными привилегиями.
— **open_basedir** в `php.ini`: ограничивает доступ PHP только к указанным директориям.
— **Валидация входных данных**: проверяйте имена файлов регулярными выражениями.

### Почему strpos() с 0 важен

Обратите внимание на `!== 0`, а не просто `!strpos()`. Если базовая директория совпадает с началом пути, `strpos` вернёт `0`, что при нестрогом сравнении трактуется как `false`. Это классическая ошибка, открывающая уязвимость.

Правильное использование `realpath()` в связке с проверкой базовой директории — один из наиболее надёжных способов защиты от Path Traversal атак в PHP-приложениях.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.