Сборка REDL: панель на PHP 8, капча-тумблер, закрытые уязвимости, установщики в один клик
- панель работает на PHP 8.4 (оригинал под PHP 7.0): elFinder utf8_encode, apache_get_modules, warnings - капча выключена и управляется из админки (флаг captcha_enable + блок настроек) - закрыты две SQL-инъекции без авторизации (createAuthLog: пароль из POST и CF-Connecting-IP) - убрано хранение паролей в открытом виде в authlog, XSS в поле ref - установщики install-panel.sh и install-node.sh (оригинальный затирал sources.list репозиториями Debian 9) - современный Dockerfile (оригинальный на debian:stretch больше не собирается) - планировщик и автозапуск работают без systemd - брендинг REDL.IO, год 2026, ссылки на redl.io - документация на русском: ИЗМЕНЕНИЯ, БЕЗОПАСНОСТЬ, ИНСТРУКЦИЯ
This commit is contained in:
+200
@@ -0,0 +1,200 @@
|
||||
# Что изменено по сравнению с оригиналом
|
||||
|
||||
Оригинал: **HostinPL 5.6** в виде «nulled»-сборки (форк `Xopowblu-4EJlOBEK/HostinPL-5.6`),
|
||||
написанной под Debian 9 и PHP 7.0.
|
||||
|
||||
Ниже — всё, что мы поменяли, с указанием файлов и строк. Правки в коде панели лежат в `panel/`.
|
||||
|
||||
**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.**
|
||||
|
||||
---
|
||||
|
||||
## 1. Панель запущена на современном PHP
|
||||
|
||||
Оригинал написан под PHP 7.0. На PHP 8 часть кода падала насмерть. Сейчас панель работает
|
||||
на **PHP 8.4**: обход всех 21 раздела (главная, сервера, новости, статус, тикеты, веб-хостинг
|
||||
и вся админка) даёт **200 на каждом и ноль ошибок в логе**.
|
||||
|
||||
| Файл | Было | Стало |
|
||||
|------|------|-------|
|
||||
| `engine/engine_ftp/elFinder.class.php:4497` | `utf8_encode()` — функция удалена в PHP 8.2, файловый менеджер падал с фатальной ошибкой | Обёрнута в `function_exists()`, фолбэк `mb_convert_encoding($str,'UTF-8','ISO-8859-1')` |
|
||||
| `application/views/admin/checksys/index.php:22` | `apache_get_modules()` — существует только в Apache с mod_php, под nginx раздел «Проверка системы» отдавал 500 | Обёрнута в `function_exists()`, иначе проверка по `REQUEST_URI` |
|
||||
| `application/views/admin/index.php:215` | `$item['invoice_ammount']` использовался после `foreach`, при пустом списке счетов — Undefined variable | Проверка `isset()` |
|
||||
| `application/models/users.php:199-206` | `$city[1]`, `$country[1]`, `$countryCode[1]` без проверки совпадения регулярки | Проверки `isset()` |
|
||||
| `application/controllers/common/loginheader.php:35` | `$_GET['ref']` без `isset` | `isset()` + приведение к `(int)` |
|
||||
|
||||
### Что оказалось ложной тревогой
|
||||
|
||||
Библиотека **phpseclib 1.x** в составе панели использует `create_function()`, удалённую в PHP 8.
|
||||
Выглядело как блокирующая проблема, но проверка показала: **phpseclib не подключается ни одним
|
||||
`include` во всей панели** — это мёртвый код. Связь с игровыми нодами идёт через нативное
|
||||
расширение `php-ssh2` (`engine/libs/ssh2.php` → `ssh2_exec`). Ничего чинить не потребовалось.
|
||||
|
||||
Так же безопасен `get_magic_quotes_gpc()` в `elFinderConnector.class.php:320` — он закрыт
|
||||
условием `version_compare(PHP_VERSION,'5.4','<') && ...`, и на PHP 8 до вызова дело не доходит.
|
||||
|
||||
---
|
||||
|
||||
## 2. Капча выключена и управляется из админки
|
||||
|
||||
Раньше капча была вшита жёстко: без валидных ключей Google **войти в панель было невозможно**,
|
||||
на форме висело «ERROR for site owner: Invalid site key». Теперь появился флаг
|
||||
`captcha_enable` в `application/config.php` (по умолчанию `0` — выключена).
|
||||
|
||||
**Бэкенд.** Во все четыре валидатора добавлена строка
|
||||
`if($this->config->captcha_enable != '1') return $result;` перед проверкой капчи:
|
||||
|
||||
* `application/controllers/account/login.php` — вход
|
||||
* `application/controllers/common/loginheader.php` — регистрация и форма обратной связи (2 места)
|
||||
* `application/controllers/tickets/create.php` — создание тикета
|
||||
|
||||
**Вёрстка.** Пять виджетов капчи (4 в `views/common/loginheader.php`, 1 в `views/tickets/create.php`)
|
||||
обёрнуты в `<?php if(@$captcha_enable == '1'): ?>`. Скрипт Google `api.js` подключается только при
|
||||
включённой капче. Все вызовы `grecaptcha.reset(...)` заменены на
|
||||
`window.grecaptcha && grecaptcha.reset(...)` — иначе при выключенной капче JavaScript падал
|
||||
в обработчиках ошибок и формы переставали отвечать.
|
||||
|
||||
**Админка.** В `views/admin/settings.php`, вкладка «Прочие настройки», добавлен блок
|
||||
«Защита от ботов (reCAPTCHA v2)»: переключатель Выключена/Включена и поля Site key и Secret key.
|
||||
|
||||
Проверено в обе стороны: при выключенной капче вход и регистрация проходят и пользователь реально
|
||||
создаётся в базе; при включённой — свежая сессия получает «Подтвердите, что вы не робот!» и виджет
|
||||
возвращается на страницу.
|
||||
|
||||
> **Осторожно при добавлении своих настроек.** Механизм сохранения настроек ищет строки конфига
|
||||
> **по подстроке** (`strpos`). Поэтому флаг назван `captcha_enable`, а не `captcha`: строка
|
||||
> `captcha` содержится в `recaptcha` и `secret_recaptcha`, и сохранение перезаписало бы не тот
|
||||
> параметр. Новые ключи не должны быть подстрокой существующих.
|
||||
|
||||
---
|
||||
|
||||
## 3. Закрыты уязвимости
|
||||
|
||||
Кратко (подробно с кодом — в [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md)):
|
||||
|
||||
* **Две SQL-инъекции, доступные без авторизации** в `application/models/users.php`
|
||||
(`createAuthLog()`): в журнал входов без экранирования попадали пароль из формы и IP из
|
||||
заголовка `CF-Connecting-IP`, который вообще не проверялся. Все значения теперь проходят через
|
||||
`$this->db->escape()` / `(int)`, заголовок проверяется `filter_var(..., FILTER_VALIDATE_IP)`.
|
||||
* **Пароли в открытом виде**: `login.php` писал реальный пароль в таблицу `authlog` при каждой
|
||||
попытке входа, включая неудачные. Убрано.
|
||||
* **XSS** в скрытом поле `ref` формы регистрации — добавлен `htmlspecialchars()`.
|
||||
* Запрос к геосервису `ip-api.com` выполняется только для валидного IP и с `urlencode()`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Установщик переписан с нуля
|
||||
|
||||
Оригинальный `install` был опасен на любой современной системе:
|
||||
|
||||
* `echo "deb ... stretch main" > /etc/apt/sources.list` — **затирал список репозиториев**
|
||||
и заменял его на Debian 9, после чего apt ломался
|
||||
* ставил `php7.0` и жёстко правил `/etc/php/7.0/apache2/php.ini`
|
||||
* переводил MariaDB на `bind-address = 0.0.0.0` без единого предупреждения
|
||||
* работал только при `/etc/issue.net` == `Debian9`, иначе просто отказывался запускаться
|
||||
* пароли и токены генерировал, но нигде не сохранял — их можно было только записать с экрана
|
||||
* при любой ошибке продолжал работу: все команды заканчивались на `> /dev/null 2>&1`
|
||||
|
||||
Новые скрипты:
|
||||
|
||||
**`install-panel.sh`** — nginx, PHP 8.x (версия определяется автоматически), MariaDB, база со
|
||||
случайным паролем, конфиг, планировщик, сторож автозапуска, создание администратора и финальная
|
||||
проверка, что страница входа действительно отдаётся с формой. Идемпотентен: повторный запуск
|
||||
не затирает уже загруженную базу. Креды пишутся в `/root/.redl-panel-credentials` (chmod 600).
|
||||
`set -euo pipefail` — при ошибке скрипт останавливается, а не делает вид, что всё хорошо.
|
||||
|
||||
**`install-node.sh`** — Docker из официального репозитория, сборка образа, каталоги
|
||||
`/home/cp/gameservers/files`, группа `gameservers`, MariaDB для баз игровых серверов, SteamCMD,
|
||||
ProFTPD, настройка sshd с откатом конфига, если `sshd -t` не проходит. **Перед началом проверяет,
|
||||
может ли Docker вообще работать на этой машине** (`unshare -Ur`), и честно предупреждает, если нет.
|
||||
В конце печатает готовые данные для подключения локации и команды файрвола.
|
||||
|
||||
Ни один из скриптов не трогает `/etc/apt/sources.list`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Образ игровых серверов пересобран
|
||||
|
||||
Оригинальный `docker/Dockerfile.original-stretch` собран на `debian:stretch`, а репозитории
|
||||
Debian 9 отключены с 2023 года — **образ больше не собирается**, `apt-get update` внутри падает.
|
||||
|
||||
Новый `docker/Dockerfile` — на Debian 12 (bookworm), но **обязательно с тегом `debian:stretch`**:
|
||||
это имя жёстко прописано в коде панели (`application/models/servers.php:642`,
|
||||
`docker create ... debian:stretch`), менять его без правки панели нельзя.
|
||||
|
||||
Что внутри: 32-битные библиотеки (SA-MP, CRMP, MTA, старые CS собраны под i386), `screen` для
|
||||
консолей, Java для Minecraft, Node.js 20 для RAGE:MP, `gdb` для разбора крашей.
|
||||
Node.js берётся из NodeSource **по HTTPS с проверкой ключа**, а не как раньше.
|
||||
|
||||
---
|
||||
|
||||
## 6. Работа без systemd
|
||||
|
||||
Панель штатно рассчитана на systemd. В контейнерных VPS его нет, поэтому добавлены сторожа
|
||||
на cron: `/usr/local/bin/hostinpl-guard` (панель) и `/usr/local/bin/gamenode-guard` (нода).
|
||||
Раз в минуту (нода — раз в 2 минуты) они проверяют MariaDB, PHP-FPM, nginx, Docker и cron и
|
||||
поднимают то, что упало; плюс задание `@reboot` для подъёма после перезагрузки.
|
||||
|
||||
Живость панели определяется **HTTP-запросом** к странице входа, а не поиском процесса по имени —
|
||||
поиск по шаблону ловил бы собственную командную строку сторожа.
|
||||
|
||||
---
|
||||
|
||||
## 7. Планировщик
|
||||
|
||||
Оригинал прописывал 9 заданий на публичный домен панели. Теперь они ходят на `127.0.0.1`
|
||||
(не зависит от DNS и внешней доступности) и получают таймауты `-m`, чтобы зависший запрос
|
||||
не копился в процессах.
|
||||
|
||||
> **Грабля с токеном.** Токен планировщика нельзя выцеплять из конфига простым `grep "'token'"` —
|
||||
> под это же условие попадает строка `'yk_password1' => 'token'`, и в URL уезжают два значения
|
||||
> через перевод строки, после чего задания молча не работают. В установщике токен пишется
|
||||
> напрямую при генерации конфига.
|
||||
|
||||
---
|
||||
|
||||
## 8. Брендинг и даты
|
||||
|
||||
* Год в подвалах: `2020©` → `2026©` (`views/common/footer.php`, `views/common/loginheader.php`)
|
||||
* Название и описание — REDL.IO: `application/config.php` (`description`, `keywords`,
|
||||
`mail_sender`, `mail_from`), подвалы, раздел «Проверка системы»
|
||||
* Ссылки на сторонние сайты прежнего владельца сборки (`hostinpl.ru`, `osmp.ga`) заменены на `redl.io`
|
||||
* Ссылки «Сообщество VK» на чужое сообщество заменены на `redl.io` (`footer.php`,
|
||||
`views/main/index.php`, `views/offline/index.php`)
|
||||
* Все 15 шаблонов писем: шапка «REDL.IO / Хостинг с искусственным интеллектом», подпись
|
||||
«С уважением, Администрация REDL.IO»
|
||||
|
||||
**Авторские копирайт-заголовки в коде не удалялись** — они остались во всех файлах,
|
||||
где были изначально.
|
||||
|
||||
---
|
||||
|
||||
## 9. phpMyAdmin
|
||||
|
||||
Панель ссылается на `/phpmyadmin` из админки. Оригинальный установщик ставил phpMyAdmin через
|
||||
Apache, что на nginx не работало. Теперь он ставится из репозитория дистрибутива и отдаётся
|
||||
самим nginx.
|
||||
|
||||
> **Грабля за обратным прокси.** nginx на адрес `/phpmyadmin` (без слеша) отвечает редиректом
|
||||
> и по умолчанию подставляет в него **собственный порт**, например
|
||||
> `http://panel.example.com:8095/phpmyadmin/`. Если панель стоит за обратным прокси, такой адрес
|
||||
> снаружи недоступен и ссылка из админки не открывается. Лечится
|
||||
> `absolute_redirect off; port_in_redirect off;` — это уже прописано в конфиге, который создаёт
|
||||
> установщик.
|
||||
|
||||
---
|
||||
|
||||
## Чего мы НЕ делали
|
||||
|
||||
* Не переписывали хеширование паролей. Панель хранит пароли как **MD5 без соли**
|
||||
(`md5($password)`, колонка `varchar(32)`). Переход на `password_hash()` затрагивает вход,
|
||||
регистрацию, восстановление, смену пароля и требует миграции существующих пользователей.
|
||||
* Не переводили создание игровых серверов с Docker на что-то другое.
|
||||
* Не удаляли `panel/application/public/js/proxy/proxy.php` — файл обезврежен, но оставлен как
|
||||
свидетельство (см. [БЕЗОПАСНОСТЬ.md](БЕЗОПАСНОСТЬ.md)).
|
||||
* Не тестировали платёжные шлюзы живыми платежами и VK-авторизацию.
|
||||
* Не проверяли работу самих игровых серверов: для этого нужна нода с Docker.
|
||||
|
||||
---
|
||||
|
||||
**Поддерживается и развивается с помощью [REDL.IO](https://redl.io) — Хостинг с искусственным интеллектом.**
|
||||
Reference in New Issue
Block a user