Цементирование сайта

Цементирование сайта

Цементирование сайта — это комплекс технических мер, которые снижают риск взлома, загрузки вредоносных файлов, чтения конфигов, эксплуатации слабого кода и несанкционированного доступа к админке.

Важно понимать, что цементирование не делает сайт неуязвимым. Если в коде есть SQL-инъекция, уязвимый плагин или плохая логика авторизации, это всё равно нужно исправлять. Но hardening резко уменьшает последствия ошибки: злоумышленнику сложнее выполнить PHP-файл, скачать .env, получить дамп базы, прочитать логи или зайти в админку.

1. Базовый принцип: защищаем не только CMS, а весь контур

У сайта есть несколько слоёв:

  1. Домен и DNS
  2. SSL / HTTPS
  3. Хостинг или VPS
  4. Веб-сервер: Apache / Nginx
  5. PHP
  6. База данных
  7. CMS / фреймворк
  8. Плагины, модули, темы
  9. Формы, загрузки файлов, админка
  10. Бэкапы, логи, доступы

Ошибка многих владельцев сайтов — думать только про CMS. Например: “Я обновил WordPress, значит всё безопасно”. На практике сайт часто ломают не через ядро CMS, а через:

  • старый плагин;
  • открытую папку uploads;
  • backup.zip в корне сайта;
  • .env в public_html;
  • chmod 777;
  • старую версию PHP;
  • слабый FTP-пароль;
  • тестовый файл разработчика;
  • открытую админку без защиты;
  • форму загрузки файлов без фильтрации.

OWASP отдельно выделяет загрузку файлов как рискованную часть приложения и рекомендует использовать allowlist расширений, проверку типа файла, переименование, ограничение размера, безопасное хранение и запрет исполнения загруженных файлов как кода.

2. Разница между shared-хостингом и VPS

Shared-хостинг

На обычном шаред-хостинге ты чаще всего можешь управлять:

  • файлами сайта;
  • .htaccess;
  • версией PHP;
  • настройками PHP через панель или .user.ini;
  • базами данных;
  • SSL;
  • cron;
  • резервными копиями;
  • FTP/SFTP-доступами.

Но обычно ты не можешь полноценно управлять:

  • системным firewall;
  • настройками Nginx/Apache на уровне сервера;
  • ModSecurity;
  • Fail2Ban;
  • PHP-FPM pools;
  • системными пользователями;
  • глобальными логами;
  • пакетами ОС.

Поэтому на shared-хостинге главный упор: .htaccess, права файлов, запрет PHP в uploads, закрытие служебных файлов, обновления CMS, бэкапы, пароли и контроль загруженных файлов.

VPS

На VPS ты уже отвечаешь за всё:

  • ОС;
  • SSH;
  • firewall;
  • веб-сервер;
  • PHP-FPM;
  • базу данных;
  • SSL;
  • логи;
  • бэкапы;
  • WAF;
  • обновления пакетов;
  • права пользователей.

Это даёт больше защиты, но и больше ответственности. Для VPS лучше ориентироваться на системные hardening-подходы: firewall, отдельные пользователи, SSH-ключи, отключение root-login, Fail2Ban, автоматические security updates, WAF и раздельные права на проекты. CIS Benchmarks описывает hardening как набор предписывающих конфигурационных рекомендаций для защиты систем и платформ.

3. Версия PHP — это первое, что нужно проверить

Старый PHP — один из главных рисков. На 6 июня 2026 года официально поддерживаются ветки PHP 8.2, 8.3, 8.4 и 8.5; PHP 8.2 получает security support до 31 декабря 2026, PHP 8.3 — до 31 декабря 2027, PHP 8.4 — до 31 декабря 2028, PHP 8.5 — до 31 декабря 2029.

Для новых проектов лучше целиться в:

PHP 8.3 / 8.4 / 8.5

Для старых CMS иногда приходится оставаться на более старой версии PHP из-за совместимости. Но это временное решение. Если сайт работает только на PHP 7.4 или 8.0, это сигнал: проект нужно обновлять, переписывать старые модули или планировать миграцию.

4. Универсальный чек-лист цементирования для любого сайта

4.1. Убрать всё лишнее из публичной папки

В публичной папке сайта не должно быть:

backup.zip
site.zip
old.zip
dump.sql
database.sql
db.sql
.env
.env.backup
config.php.bak
composer.json
composer.lock
package.json
node_modules/
.git/
.svn/
.idea/
.vscode/
logs/

Публичная папка — это то, что открывается из браузера. На shared-хостинге это обычно:

public_html/
www/
htdocs/

На VPS это может быть:

/var/www/site/public
/var/www/site/public_html
/home/site/web/domain.com/public_html

Бэкапы нужно хранить выше публичной папки:

/home/user/backups/
/var/backups/site/

4.2. Права на файлы и папки

Базовый стандарт:

Папки: 755
Файлы: 644
Конфиги: 600 или 640

Команды для SSH:

find public_html -type d -exec chmod 755 {} \;
find public_html -type f -exec chmod 644 {} \;

Для важных файлов:

chmod 600 .env
chmod 600 configuration.php
chmod 600 wp-config.php
chmod 600 config.php

Плохая практика:

chmod 777

777 можно использовать только в крайних случаях и временно. Если CMS требует 777, чаще всего проблема не в CMS, а в неправильном владельце файлов или настройках PHP/Apache.

4.3. Запрет просмотра директорий

Если в папке нет index.php, пользователь не должен видеть список файлов.

Для Apache в корневом .htaccess:

Options -Indexes

Для Nginx:

autoindex off;

4.4. Закрытие служебных файлов через .htaccess

Файл:

public_html/.htaccess

Базовый вариант:

Options -Indexes

<FilesMatch "^\.">
    Require all denied
</FilesMatch>

<FilesMatch "(^#.*#|\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|orig|save)|~)$">
    Require all denied
</FilesMatch>

<FilesMatch "^(composer\.(json|lock)|package(-lock)?\.json|yarn\.lock|webpack\.mix\.js|vite\.config\.js|artisan|\.env)$">
    Require all denied
</FilesMatch>

RedirectMatch 404 /\.git
RedirectMatch 404 /\.svn
RedirectMatch 404 /node_modules
RedirectMatch 404 /vendor

Этот блок не заменяет правильную структуру проекта, но закрывает типовые ошибки.

4.5. Запрет выполнения PHP в uploads

Это один из самых важных пунктов.

Папки загрузок:

/uploads/
/upload/
/files/
/media/
/images/
/wp-content/uploads/
/sites/default/files/
/assets/
/storage/app/public/

Внутри каждой такой папки для Apache нужно положить .htaccess:

Options -Indexes

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar|cgi|pl|py|sh|shtml)$">
    Require all denied
</FilesMatch>

RemoveHandler .php .php3 .php4 .php5 .php7 .php8 .phtml .phar
RemoveType .php .php3 .php4 .php5 .php7 .php8 .phtml .phar

Смысл: даже если через слабую форму кто-то загрузит файл с опасным расширением, сервер не должен выполнить его как код.

Для Nginx на VPS аналогично:

location ~* ^/(uploads|upload|files|media|images|wp-content/uploads|assets)/.*\.(php|phtml|phar|cgi|pl|py|sh)$ {
    deny all;
}

4.6. Безопасная загрузка файлов

Разрешай только то, что действительно нужно бизнесу.

Обычно можно разрешить:

jpg
jpeg
png
webp
pdf
doc
docx
xls
xlsx

Лучше запретить:

php
phtml
phar
js
html
htm
svg
sh
cgi
pl
py
exe
bat
cmd

SVG лучше не принимать от пользователей, если нет отдельной очистки, потому что SVG — это не просто картинка, а XML-формат, который может нести активное содержимое.

Файлы после загрузки лучше переименовывать:

Было:
document.php.jpg

Стало:
a83f9c1d7e2b.jpg

Нельзя доверять только расширению файла. Нужно проверять размер, MIME/type, реальное содержимое, путь сохранения и права доступа. OWASP рекомендует строить защиту загрузок по принципу нескольких слоёв: allowlist, проверка файла, безопасное имя, ограничение размера, хранение вне опасного контекста и защита от исполнения.

4.7. Настройки PHP

На shared-хостинге часто можно создать файл:

.user.ini

Пример:

display_errors = Off
log_errors = On
expose_php = Off
upload_max_filesize = 10M
post_max_size = 12M
max_execution_time = 60
memory_limit = 256M

Если сайт вообще не принимает загрузку файлов:

file_uploads = Off

На VPS настройки обычно лежат в:

/etc/php/8.3/fpm/php.ini
/etc/php/8.3/apache2/php.ini
/etc/php/8.3/fpm/pool.d/site.conf

После правок PHP-FPM:

sudo systemctl reload php8.3-fpm

4.8. Отключить вывод ошибок на экран

На боевом сайте нельзя показывать пользователям:

SQLSTATE...
/home/user/public_html/...
Stack trace...
DB_PASSWORD...
APP_KEY...

Правильно:

display_errors = Off
log_errors = On

Для Laravel:

APP_ENV=production
APP_DEBUG=false

Laravel прямо указывает, что APP_DEBUG в production должен быть false, иначе можно раскрыть чувствительные конфигурационные значения пользователям.

4.9. HTTPS и редирект

На Apache:

RewriteEngine On

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

HSTS включай только если уверен, что сайт и поддомены корректно работают по HTTPS:

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</IfModule>

Для Nginx:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

4.10. Security headers

Для Apache:

<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

Для Nginx:

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

OWASP Secure Headers Project описывает HTTP security headers как дополнительный слой защиты, который помогает браузеру ограничивать часть легко предотвращаемых рисков.

5. Цементирование на shared-хостинге

На shared-хостинге делай так:

Шаг 1. Проверить версию PHP

В панели хостинга:

  • PHP Selector
  • MultiPHP Manager
  • Настройки PHP
  • Версия PHP

Выбери актуальную совместимую версию. Для старых сайтов сначала тестируй на копии.

Шаг 2. Проверить публичные файлы

Открой в браузере:

site.kz/.env
site.kz/composer.json
site.kz/composer.lock
site.kz/backup.zip
site.kz/database.sql
site.kz/.git/config
site.kz/wp-config.php
site.kz/configuration.php

Нормальный результат:

403 Forbidden
404 Not Found

Плохой результат — если файл скачивается или открывается.

Шаг 3. Поставить .htaccess в корень

Используй универсальный блок из раздела выше.

Шаг 4. Поставить .htaccess в папки загрузок

Особенно:

/wp-content/uploads/
/upload/
/uploads/
/assets/
/media/
/files/
/images/

Шаг 5. Проверить права

В файловом менеджере хостинга:

Папки: 755
Файлы: 644
Конфиги: 600/640

Шаг 6. Отключить FTP, если есть SFTP

FTP передаёт данные менее безопасно. Лучше использовать SFTP/SSH, если хостинг позволяет.

Шаг 7. Сделать отдельные доступы

Нельзя давать всем один логин от хостинга. Для разработчика, SEO-специалиста, контент-менеджера и подрядчика — разные доступы, если панель позволяет.

Шаг 8. Бэкапы вне public_html

Если хостинг создаёт архив в корне сайта, сразу скачай и удали его из публичной папки.

6. Цементирование на VPS

На VPS схема жёстче.

6.1. Обновить систему

Ubuntu/Debian:

sudo apt update
sudo apt upgrade -y

6.2. Создать отдельного пользователя

adduser deploy
usermod -aG sudo deploy

Не работай постоянно под root.

6.3. SSH-защита

Файл:

/etc/ssh/sshd_config

Минимально:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

После правки:

sudo systemctl reload ssh

Важный момент: перед отключением паролей проверь, что вход по SSH-ключу точно работает.

6.4. Firewall через UFW

Ubuntu описывает ufw как пользовательский способ управлять firewall-правилами для IPv4/IPv6.

Базовый набор:

sudo ufw default deny incoming
sudo ufw default allow outgoing

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable
sudo ufw status verbose

6.5. Fail2Ban

Fail2Ban следит за логами и может блокировать IP-адреса при повторяющихся неудачных попытках входа; это полезно против перебора паролей и автоматических атак на SSH/админки.

Установка:

sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Базовая проверка:

sudo fail2ban-client status

6.6. WAF / ModSecurity / OWASP CRS

На VPS можно поставить ModSecurity + OWASP Core Rule Set. OWASP CRS — это набор универсальных правил для WAF, предназначенный для обнаружения типовых атак на веб-приложения, включая категории вроде SQL Injection, XSS и Local File Inclusion.

Но включать WAF лучше поэтапно:

  1. Сначала detection/logging mode.
  2. Проверить ложные срабатывания.
  3. Настроить исключения под CMS.
  4. Потом включать blocking mode.

Иначе можно случайно сломать админку, оплату, фильтры каталога, формы или API.

7. WordPress цементирование

WordPress — самая популярная CMS, поэтому её постоянно сканируют боты. Официальный WordPress hardening guide подчёркивает, что безопасность требует базовых мер: обновлений, контроля доступа, правильной настройки файлов и снижения поверхности атаки.

7.1. Что обновить

  • ядро WordPress;
  • плагины;
  • темы;
  • переводы;
  • PHP;
  • серверные пакеты, если VPS.

Удаляй всё неиспользуемое:

  • старые темы;
  • отключённые плагины;
  • тестовые плагины;
  • nulled-темы;
  • nulled-плагины.

Nulled-темы и плагины — один из частых источников заражения.

7.2. Защита wp-config.php

Права:

chmod 600 wp-config.php

В .htaccess:

<Files wp-config.php>
    Require all denied
</Files>

7.3. Запрет редактирования файлов из админки

В wp-config.php:

define('DISALLOW_FILE_EDIT', true);

Более жёсткий вариант:

define('DISALLOW_FILE_MODS', true);

Но второй вариант отключит установку и обновление плагинов/тем через админку. Используй только если процесс обновлений идёт через Git/SSH.

7.4. Защита uploads

Файл:

wp-content/uploads/.htaccess

Содержимое:

Options -Indexes

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar|cgi|pl|py|sh|shtml)$">
    Require all denied
</FilesMatch>

RemoveHandler .php .php3 .php4 .php5 .php7 .php8 .phtml .phar
RemoveType .php .php3 .php4 .php5 .php7 .php8 .phtml .phar

7.5. Админка

Минимум:

  • не использовать логин admin;
  • включить 2FA;
  • ограничить попытки входа;
  • поставить сложные пароли;
  • отключить старых пользователей;
  • не давать администратора контент-менеджеру;
  • закрыть /wp-admin по IP или Basic Auth, если это корпоративный сайт.

Для Basic Auth на Apache:

7.6. XML-RPC

Если не используешь мобильное приложение, Jetpack или внешние интеграции, можно ограничить xmlrpc.php.

<Files xmlrpc.php>
    Require all denied
</Files>

Но сначала проверь, не завязаны ли на него интеграции.

8. Bitrix / 1C-Bitrix: цементирование

У Bitrix часто проблема не только в CMS, а в тяжёлой инфраструктуре, старых модулях, кастомном коде, открытой админке и папке /upload/.

Для Bitrix-семейства важно использовать встроенные инструменты безопасности. Bitrix24 Helpdesk описывает proactive protection как встроенный WAF, который блокирует распространённые веб-атаки.

8.1. Что проверить в первую очередь

  • версия ядра;
  • обновления модулей;
  • Marketplace-модули;
  • кастомные компоненты;
  • права на /upload/;
  • открытость /bitrix/admin/;
  • наличие старых backup-архивов;
  • тестовые файлы разработчиков;
  • дампы базы в корне сайта.

8.2. Папка upload

Для Apache:

/upload/.htaccess
Options -Indexes

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar|cgi|pl|py|sh|shtml)$">
    Require all denied
</FilesMatch>

RemoveHandler .php .php3 .php4 .php5 .php7 .php8 .phtml .phar
RemoveType .php .php3 .php4 .php5 .php7 .php8 .phtml .phar

На Bitrix это особенно важно, потому что /upload/ часто содержит пользовательские файлы, картинки, документы, временные выгрузки и импортированные материалы.

8.3. Админка

Админка /bitrix/admin/

Что сделать:

  • сложный пароль;
  • 2FA, если доступно;
  • отдельные роли;
  • не давать всем полный административный доступ;
  • закрыть по IP, если админка нужна только офису;
  • дополнительно закрыть Basic Auth.

8.4. Убрать опасные файлы

Проверить:

/bitrixsetup.php
/restore.php
/backup/
/upload/backup/
/local/backup/
/dump.sql
/site.zip
/old.zip

После установки и восстановления такие файлы не должны оставаться публично доступными.

8.5. На VPS

Для Bitrix на VPS лучше:

  • отдельный пользователь под сайт;
  • отдельный PHP-FPM pool;
  • OPcache;
  • HTTPS;
  • firewall;
  • Fail2Ban;
  • WAF;
  • регулярные бэкапы;
  • мониторинг места на диске;
  • мониторинг логов PHP и веб-сервера.

9. Joomla цементирование

Joomla в официальном Security Checklist рекомендует устанавливать официальные версии, менять стандартного администратора, защищать директории и файлы, а также корректно настраивать права.

9.1. Обновления

Проверить:

  • Joomla core;
  • расширения;
  • шаблоны;
  • языковые пакеты;
  • сторонние компоненты;
  • старые отключённые расширения.

Удалить всё, что не используется.

9.2. configuration.php

Файл:

configuration.php

Права:

chmod 600 configuration.php

В .htaccess:

<Files configuration.php>
    Require all denied
</Files>

9.3. Админка

Админка Joomla: /administrator/

Защита:

  • 2FA;
  • сложные пароли;
  • не использовать стандартные логины;
  • ограничить попытки входа;
  • закрыть /administrator/ по IP или Basic Auth.

Joomla в пользовательском security guide также рекомендует использовать security extensions, в том числе для ограничения попыток входа в административную часть.

9.4. Папки загрузок

Типовые папки:

/images/
/media/
/tmp/
/logs/

tmp и logs лучше выносить за пределы публичной директории, если хостинг позволяет. В папках с изображениями запретить PHP.

9.5. Права

Папки: 755
Файлы: 644
configuration.php: 600

10. Drupal: цементирование

Drupal официально ведёт раздел “Securing your site” и подчёркивает, что безопасность — это постоянный процесс: нужно обновлять код Drupal и инфраструктуру, а не один раз настроить сайт и забыть.

10.1. Обновления

Проверить:

  • Drupal core;
  • contributed modules;
  • themes;
  • composer dependencies;
  • PHP;
  • Drush;
  • серверные пакеты.

Drupal рекомендует включить Update Manager и настроить уведомления о доступных обновлениях на реальный email.

10.2. settings.php

Файл:

sites/default/settings.php

Права:

chmod 440 sites/default/settings.php

Или, если хостинг не позволяет:

chmod 400 sites/default/settings.php

10.3. files directory

Публичные файлы обычно:

sites/default/files/

Там должен быть .htaccess, который Drupal обычно создаёт сам. Но нужно проверить, что PHP там не выполняется.

Дополнительно можно поставить:

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar)$">
    Require all denied
</FilesMatch>

10.4. Private files

Для документов, которые не должны открываться напрямую, используй private files directory вне webroot:

/home/user/private_files

А не:

public_html/sites/default/files/private

10.5. Trusted host settings

В settings.php укажи разрешённые домены:

$settings['trusted_host_patterns'] = [
  '^example\.kz$',
  '^www\.example\.kz$',
];

Это снижает риски, связанные с неправильным Host header.

11. MODX Revolution: цементирование

MODX официально выделяет четыре главных направления hardening: защитить core, защитить manager, поставить firewall/WAF и обновлять сервер, MODX и Extras.

11.1. Защитить core

Папка /core/

Она не должна быть доступна из браузера.

Для Apache:

RewriteRule ^core/ - [F,L]
RewriteRule ^config.core.php - [F,L]

Более скрытый вариант — отдавать 404:

RewriteRule ^(core|config.core.php) /index.php?q=doesnotexist [L,R=404]

MODX в документации прямо указывает, что core нужно блокировать от публичного доступа.

11.2. Защитить manager

Стандартный путь: /manager/

Что сделать:

  • закрыть по IP;
  • добавить Basic Auth;
  • переименовать/перенести manager, если проект позволяет;
  • включить сложные пароли;
  • убрать стандартные логины.

MODX рекомендует защищать Manager, в том числе ограничивать доступ по IP или ставить дополнительную .htaccess-авторизацию.

11.3. Обновления

Обновлять:

  • MODX core;
  • Extras;
  • PHP;
  • сервер;
  • Composer-зависимости, если используются.

11.4. Assets

Папка /assets/

Там запретить выполнение PHP:

Options -Indexes

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar)$">
    Require all denied
</FilesMatch>

12. Laravel цементирование

Laravel нужно деплоить так, чтобы публичной была только папка public. Официальная документация Laravel прямо предупреждает: веб-сервер должен направлять все запросы в public/index.php, а попытка обслуживать приложение из корня проекта может раскрыть чувствительные конфигурационные файлы в интернет.

12.1. Правильная структура

Правильно:

/home/user/project/
├── app/
├── bootstrap/
├── config/
├── database/
├── public/
│   └── index.php
├── resources/
├── routes/
├── storage/
├── vendor/
└── .env

Домен должен смотреть сюда:

/home/user/project/public

Неправильно:

/home/user/project

Если домен смотрит в корень Laravel-проекта, могут быть доступны .env, composer.json, storage, vendor и другие чувствительные файлы.

12.2. .env

APP_ENV=production
APP_DEBUG=false

Права:

chmod 600 .env

12.3. Установка зависимостей

На production:

composer install --no-dev --optimize-autoloader

12.4. Кэширование

php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache

Laravel описывает эти команды как часть production deployment/optimization.

12.5. Права

Писать должны только:

storage/
bootstrap/cache/

Пример:

chmod -R 775 storage bootstrap/cache

Остальной проект не должен быть writable для веб-сервера.

12.6. Защита storage

Если используется:

php artisan storage:link

то публичной становится:

public/storage

Туда нельзя позволять загружать PHP и исполняемые файлы. На Apache:

public/storage/.htaccess
Options -Indexes

<FilesMatch "\.(php|php3|php4|php5|php7|php8|phtml|phar|cgi|pl|py|sh|shtml)$">
    Require all denied
</FilesMatch>

13. Готовый универсальный .htaccess для Apache

Можно использовать как базу и адаптировать под CMS:

Options -Indexes

RewriteEngine On

# HTTPS redirect
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Security headers
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

# Deny dotfiles
<FilesMatch "^\.">
    Require all denied
</FilesMatch>

# Deny backups, dumps, logs, configs
<FilesMatch "(^#.*#|\.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|orig|save)|~)$">
    Require all denied
</FilesMatch>

# Deny common project files
<FilesMatch "^(composer\.(json|lock)|package(-lock)?\.json|yarn\.lock|webpack\.mix\.js|vite\.config\.js|artisan|\.env)$">
    Require all denied
</FilesMatch>

RedirectMatch 404 /\.git
RedirectMatch 404 /\.svn
RedirectMatch 404 /node_modules

14. Готовый Nginx-блок для VPS

Примерный фрагмент:

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.php index.html;

    autoindex off;

    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

    location ~ /\.(?!well-known) {
        deny all;
    }

    location ~* \.(bak|config|sql|ini|log|sh|inc|swp|dist|old|orig|save)$ {
        deny all;
    }

    location ~* /(composer\.(json|lock)|package(-lock)?\.json|yarn\.lock|webpack\.mix\.js|vite\.config\.js|artisan|\.env)$ {
        deny all;
    }

    location ~* ^/(uploads|upload|files|media|images|wp-content/uploads|assets|storage)/.*\.(php|phtml|phar|cgi|pl|py|sh)$ {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}

Nginx поддерживает добавление произвольных заголовков через модуль ngx_http_headers_module и директиву add_header.

15. База данных

Для каждого сайта — отдельная база и отдельный пользователь.

Минимальные права для обычной работы:

SELECT
INSERT
UPDATE
DELETE

Для миграций и обновлений могут понадобиться:

CREATE
ALTER
DROP
INDEX

Но не нужно держать максимальные права постоянно, если проект этого не требует.

Пароль базы:

  • длинный;
  • уникальный;
  • не совпадает с FTP;
  • не совпадает с админкой;
  • не отправляется в Telegram/WhatsApp открытым текстом.

16. Бэкапы

Правильная схема:

  • Ежедневно: база данных
  • Еженедельно: файлы сайта
  • Перед обновлением: полный бэкап
  • После крупных правок: контрольный бэкап

Хранить:

  • вне public_html;
  • на отдельном диске;
  • в облаке;
  • с ограниченным доступом.

Нельзя:

public_html/backup.zip public_html/site-old.zip public_html/db.sql public_html/dump.sql

17. Мониторинг подозрительных файлов

На VPS или shared с SSH:

Новые PHP-файлы за 7 дней

find public_html -type f -name "*.php" -mtime -7

PHP в uploads

find public_html -type f \( -path "*uploads*" -o -path "*upload*" -o -path "*files*" -o -path "*media*" \) \( -name "*.php" -o -name "*.phtml" -o -name "*.phar" \)

Архивы и дампы в public_html

find public_html -type f \( -name "*.zip" -o -name "*.rar" -o -name "*.tar" -o -name "*.gz" -o -name "*.sql" \)

Подозрительные недавно изменённые файлы

find public_html -type f -mtime -3

Это не антивирус, но для регулярного контроля очень полезно.

18. Чек-лист для агентства перед запуском сайта

  1. PHP актуальный и совместимый
  2. HTTPS включён
  3. HTTP редиректит на HTTPS
  4. Нет backup.zip / dump.sql / .env в public_html
  5. Папки 755
  6. Файлы 644
  7. Конфиги 600/640
  8. Нет chmod 777
  9. display_errors выключен
  10. log_errors включён
  11. uploads не выполняет PHP
  12. .git закрыт
  13. composer.json закрыт
  14. package.json закрыт
  15. админка защищена
  16. у всех пользователей свои доступы
  17. старые плагины удалены
  18. nulled-решений нет
  19. бэкап настроен
  20. восстановление бэкапа проверено
  21. WAF включён или запланирован
  22. логирование работает
  23. формы имеют валидацию и CSRF
  24. файлы загружаются только по allowlist

19. Главные ошибки, которые нельзя допускать

  • Оставлять архив сайта в корне
  • Оставлять дамп базы в public_html
  • Делать chmod 777 на весь сайт
  • Держать APP_DEBUG=true
  • Оставлять старые плагины
  • Использовать nulled-темы
  • Давать всем один FTP
  • Работать через обычный FTP вместо SFTP
  • Не обновлять PHP
  • Не проверять /uploads/
  • Не закрывать .env
  • Хранить бэкапы в публичной папке
  • Давать контент-менеджеру права администратора
  • Не делать бэкап перед обновлением

20. Короткая стратегия по каждому типу проекта

Shared-хостинг

  1. Обновить PHP.
  2. Закрыть служебные файлы через .htaccess.
  3. Запретить PHP в uploads.
  4. Проверить права файлов.
  5. Удалить бэкапы из public_html.
  6. Обновить CMS и плагины.
  7. Защитить админку.
  8. Настроить бэкапы.

VPS

  1. Обновить ОС.
  2. Настроить SSH-ключи.
  3. Отключить root-login.
  4. Включить firewall.
  5. Поставить Fail2Ban.
  6. Настроить Nginx/Apache.
  7. Настроить PHP-FPM.
  8. Разделить пользователей и проекты.
  9. Подключить WAF.
  10. Настроить логи и бэкапы.

WordPress

  1. Обновить ядро, плагины, темы.
  2. Удалить лишнее.
  3. Защитить wp-config.php.
  4. Запретить редактирование файлов.
  5. Защитить wp-content/uploads.
  6. Включить 2FA.

Bitrix

  1. Обновить ядро и модули.
  2. Проверить /upload/.
  3. Удалить restore.php, bitrixsetup.php и архивы.
  4. Защитить /bitrix/admin/.
  5. Включить встроенные механизмы безопасности.
  6. Проверить кастомные компоненты.

Joomla

  1. Обновить Joomla и расширения.
  2. Защитить configuration.php.
  3. Защитить /administrator/.
  4. Проверить /images/, /media/, /tmp/, /logs/.
  5. Удалить неиспользуемые расширения.

Drupal

  1. Обновить core/modules/themes.
  2. Настроить Update Manager.
  3. Защитить settings.php.
  4. Проверить sites/default/files.
  5. Настроить private files.
  6. Настроить trusted_host_patterns.

MODX Revo

  1. Закрыть /core/.
  2. Защитить /manager/.
  3. Обновить MODX и Extras.
  4. Защитить /assets/.
  5. Подключить WAF.

Laravel

  1. Домен должен смотреть только в /public.
  2. APP_DEBUG=false.
  3. .env вне public.
  4. composer install —no-dev.
  5. config/cache/route/view cache.
  6. storage и bootstrap/cache writable, остальное закрыто.
  7. public/storage не выполняет PHP.

Подведём итоги

Цементирование сайта — это не одна кнопка и не один плагин. Это система: обновления, права, запрет выполнения файлов, закрытые конфиги, защищённая админка, HTTPS, WAF, бэкапы и мониторинг.

Самые важные меры, которые дают максимальный эффект:

  1. Запретить PHP в uploads.
  2. Убрать .env, .sql, .zip из public_html.
  3. Отключить display_errors.
  4. Обновить PHP и CMS.
  5. Защитить админку.
  6. Убрать chmod 777.
  7. Настроить бэкапы вне сайта.
  8. На VPS включить firewall, Fail2Ban и WAF.

Если внедрить хотя бы эти пункты, сайт станет намного устойчивее к типовым автоматическим атакам, заражениям через загрузки, утечкам конфигов и ошибкам разработчиков.

Роман Бондарь

Более 15 лет работаю с сайтами, SEO и веб-проектами. Параллельно всегда занимался безопасностью сайтов и цифровых активов, понимая, как легко потерять доход из-за ошибок, уязвимостей и неправильных решений. Пишу о деньгах, интернете и рисках так, как они выглядят в реальности — без теории, обещаний и иллюзий.