Безпека

Безпека

Безпека в Celena не опційна — це набір обовʼязкових практик. Нижче — що використовувати і чого не робити.

Валідація введення

Будь-яке введення користувача проходить через Celena\Core\Security\Filter:

use Celena\Core\Security\Filter;

$name  = Filter::string((string) $request->input('name'));
$slug  = Filter::urlSlug((string) $request->input('slug'));
$email = Filter::email((string) $request->input('email'));
$id    = (int) $request->input('id');

Не довіряйте $_GET/$_POST напряму — беріть через $request->input()/query() і фільтруйте.

SQL-інʼєкції

Лише підготовлені вирази та QueryBuilder. Конкатенація значень у SQL заборонена.

// ПРАВИЛЬНО
$conn->builder('users')->where('email', '=', $email)->first();
$conn->run('SELECT * FROM ' . $conn->table('users') . ' WHERE id = ?', [$id]);

// НЕБЕЗПЕЧНО — так не можна
$conn->run("SELECT * FROM users WHERE email = '$email'");

XSS — виведення в HTML

У шаблонах змінні екрануються автоматично ({var}). Сире виведення ({var|raw}) — лише для довіреного HTML. У PHP використовуйте хелпер e():

echo e($userText);          // безпечно
echo $userText;             // НЕБЕЗПЕЧНО, якщо це введення користувача

Markdown-рендерер ядра екранує початковий HTML — користувацький markdown не може виконати <script>.

CSRF

Форми та AJAX-запити захищені токеном. У шаблоні:

<form method="post">{csrf} … </form>     <!-- прихований інпут _csrf -->
{csrf format="meta"}                       <!-- мета-тег для fetch/AJAX -->

На сервері:

use Celena\Core\Security\Csrf;
if (!Csrf::validate((string) $request->input('_csrf'))) {
    return Response::json(['error' => 'csrf'], 419);
}

Автентифікація та ролі

  • Паролі зберігаються як Argon2id (Celena\Core\Security\Password). У відкритому вигляді не зберігаються ніде.
  • Вхід — /admin/login. Користувачі — у таблиці cl_celena_users.
  • Ролі: admin (усе), editor, author, user, customer. Перевірка прав:
use Celena\Core\Security\Permission;
if (!Permission::can($user, 'news.update')) {
    return Response::redirect('/admin/login');
}

Адмінські контролери перевіряють $this->auth->user() на початку дії.

Обмеження частоти

Celena\Core\Security\RateLimiter захищає чутливі ручки (логін, приймання заявок, публічний API) від перебору:

$limiter = $container->make(RateLimiter::class);
if (!$limiter->attempt('login_' . $request->ip(), 5, 60)) {  // 5 спроб за хвилину
    return Response::json(['error' => 'rate_limited'], 429);
}

Завантаження файлів і zip

  • Перевіряйте MIME/розширення завантажуваних файлів; не віддавайте їх як виконувані.
  • Встановлювач плагінів перевіряє архіви на ZIP-Slip (вихід за межі теки), блокує .phar, валідує manifest.json. Ці самі перевірки повторюйте при будь-якому розпакуванні користувацьких архівів.

CSP і зовнішні ресурси

Політика безпеки контенту (CSP) пускає скрипти лише з 'self' і довірених доменів (Google-сервіси). Зовнішні CDN (jQuery, шрифти, віджети) заблоковані — зберігайте асети локально. На сайті немає jQuery.

.htaccess і сервер

Не використовуйте в .htaccess директиви <Directory> чи php_flag при роботі з PHP-FPM — це ламає Apache (помилка 500). Кеш-заголовки статики налаштовуються на рівні nginx, а не в .htaccess.