Базовая защита сервера (оборонительно)

Минимальный набор настроек, который превращает свежий VPS из «открытой двери» в нормально защищённый сервер. Всё — про защиту собственной машины.

Hardening (укрепление) — приведение системы к более безопасному состоянию по умолчанию: сокращение поверхности атаки, усиление аутентификации и ограничение прав, чтобы случайная или автоматическая атака не достигла цели.

Свежеразвёрнутый сервер в интернете начинают перебирать боты в течение минут: в логах sshd почти сразу появляются тысячи попыток входа под root с типичными паролями. Это фоновый шум сети, и единственная защита от него — заранее закрыть очевидные двери. Ниже — оборонительная база: обновления, ключи вместо паролей, ограничение root, файрвол, защита от перебора, минимум привилегий и аудит того, что вообще слушает порты. Каждый пункт — про вашу машину и её устойчивость.

1. Своевременные обновления

Большинство взломов используют уже известные и давно закрытые уязвимости — на серверах, которые просто не обновили. Поэтому регулярное обновление пакетов (особенно openssh, ядра, библиотек вроде openssl) — самая результативная и дешёвая мера безопасности.

# Debian/Ubuntu: обновить список и пакеты
sudo apt update && sudo apt upgrade -y

# Автоматические security-обновления без ручного вмешательства
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# Fedora/RHEL
sudo dnf upgrade --refresh -y

unattended-upgrades сам ставит критические патчи безопасности — для сервера, за которым не следят ежедневно, это разумная страховка.

2. Вход по SSH-ключам вместо пароля

Пароль можно подобрать перебором; ключевую пару из 4096-битного RSA или Ed25519 — практически нет. Идея: приватный ключ остаётся у вас, публичный кладётся на сервер, и доступ получает лишь владелец приватного ключа.

# НА СВОЁМ компьютере: сгенерировать пару ключей
ssh-keygen -t ed25519 -C "me@laptop"

# Скопировать ПУБЛИЧНЫЙ ключ на сервер (добавит его в authorized_keys)
ssh-copy-id user@server

# Проверить, что вход по ключу работает, ДО отключения паролей
ssh user@server

После того как вход по ключу проверен, парольную аутентификацию отключают в конфиге демона sshd — тогда подбор пароля становится бессмысленным:

# /etc/ssh/sshd_config — задать значения:
# PasswordAuthentication no
# PubkeyAuthentication yes

sudo systemctl restart ssh     # применить (на части систем сервис называется sshd)

3. Отключение входа root по SSH

root есть на каждой Linux-машине, поэтому именно его логин боты перебирают первым. Правильная схема — заходить под обычным пользователем и повышать права через sudo по необходимости. Вход root по SSH запрещают директивой PermitRootLogin no:

# /etc/ssh/sshd_config:
# PermitRootLogin no

sudo systemctl restart ssh

Перед этим убедитесь, что у вашего обычного пользователя есть sudo (он состоит в группе sudo на Debian/Ubuntu или wheel на Fedora/RHEL), иначе вы рискуете отрезать себе администрирование:

id $USER                       # проверить группы пользователя
sudo usermod -aG sudo alice    # дать пользователю alice права sudo (Debian/Ubuntu)

4. Настройка файрвола

Файрвол закрывает всё лишнее: наружу должны торчать только те порты, которые реально нужны (обычно SSH и порты вашего приложения). На Ubuntu это удобнее всего делать через ufw, на Fedora/RHEL — через firewalld.

# ufw (Ubuntu): политика по умолчанию — всё входящее запретить, исходящее разрешить
sudo ufw default deny incoming
sudo ufw default allow outgoing

# открыть только нужное
sudo ufw allow OpenSSH         # или: sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable                # включить файрвол
sudo ufw status verbose        # проверить правила

Важно: сначала разрешите SSH, и только потом включайте файрвол, иначе закроете себе вход. На firewalld та же логика:

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

5. fail2ban против перебора

Даже с ключами лог sshd забивают тысячи неудачных попыток. fail2ban читает логи, и если с одного IP идёт серия неудачных входов — временно блокирует этот адрес правилом файрвола. Это снижает шум и тормозит перебор:

sudo apt install fail2ban

# базовая настройка в /etc/fail2ban/jail.local (НЕ правят jail.conf):
# [sshd]
# enabled = true
# maxretry = 5          # сколько промахов до бана
# bantime = 1h          # на сколько банить
# findtime = 10m        # окно, в котором считаются промахи

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd      # сколько адресов забанено

6. Принцип минимальных привилегий

Базовое правило безопасности: каждый процесс и пользователь должен иметь ровно столько прав, сколько нужно для работы, и ни на йоту больше. Тогда взлом или ошибка одного компонента не отдаёт атакующему всю систему. На практике:

  • Не работайте под root постоянно — обычный пользователь плюс sudo точечно.
  • Сервисы (веб-сервер, БД) запускайте под выделенными непривилегированными пользователями (www-data, postgres), а не под root.
  • Давайте на файлы минимально необходимые права (вспомните chmod): приватный ключ — 600, конфиги — без записи для посторонних.
  • Удаляйте/не ставьте лишние пакеты и сервисы — чего нет, то не взломают.
chmod 600 ~/.ssh/id_ed25519    # приватный ключ — только владельцу
ps -eo user,comm | sort -u | head   # под какими пользователями крутятся процессы

7. Аудит открытых портов через ss

Нельзя защитить то, о чём не знаешь. Поэтому регулярно проверяйте, какие службы реально слушают сеть. Современная утилита для этого — ss (замена устаревшего netstat):

sudo ss -tulpn
#  -t TCP   -u UDP   -l только слушающие   -p процесс/PID   -n числовые порты

Вывод: (пример)

Netid State  Local Address:Port  Process
tcp   LISTEN 0.0.0.0:22          users:(("sshd",pid=701))
tcp   LISTEN 127.0.0.1:5432      users:(("postgres",pid=820))

Главное, на что смотреть, — адрес, на котором висит служба. 0.0.0.0 (или *) означает «слушаю на всех интерфейсах, доступен из интернета»; 127.0.0.1 — «только локально». В примере PostgreSQL слушает лишь localhost — это хорошо: база не должна торчать наружу. Если служба, которой не нужен внешний доступ, висит на 0.0.0.0 — это лишняя открытая дверь: ограничьте её привязкой к 127.0.0.1 в конфиге сервиса и/или закройте файрволом.

Как это работает под капотом

Эшелонированная оборона строится слоями, и каждый пункт закрывает свой уровень. Файрвол (ufw/firewalld) — это удобная обёртка над nftables/iptables в ядре: пакеты на запрещённые порты ядро отбрасывает ещё до того, как они дойдут до приложения, поэтому неоткрытого порта для атакующего как бы не существует. Аутентификация по ключам опирается на асимметричную криптографию: сервер шлёт клиенту случайный вызов, тот подписывает его приватным ключом, а сервер проверяет подпись публичным — приватный ключ при этом никогда не передаётся по сети, поэтому и перехватывать нечего. fail2ban работает на уровень выше: он парсит лог sshd и при серии промахов с одного IP сам добавляет временное блокирующее правило в тот же файрвол. А принцип минимальных привилегий ограничивает ущерб, если внешний слой всё же пробит: процесс под www-data, вырвавшийся из веб-приложения, не имеет прав root и не доберётся до системных файлов. Ни один слой не идеален поодиночке — устойчивость даёт именно их сумма.

Частые ошибки

  • Включают файрвол, не разрешив предварительно SSH, — и теряют доступ к серверу.
  • Отключают парольный вход до проверки, что ключ работает, — и запирают себя снаружи.
  • Запрещают вход root, не убедившись, что у обычного пользователя есть sudo, — остаются без администрирования.
  • Считают, что fail2ban заменяет ключи: это лишь тормоз перебора, а не аутентификация — ключи и отключение паролей важнее.
  • Не проверяют ss -tulpn и не замечают, что БД или отладочный сервис висит на 0.0.0.0 и доступен из интернета.
  • Хранят приватный ключ с открытыми правами (не 600) — SSH вообще откажется его использовать, и это правильно.

Итоги

  • Регулярные обновления (вкл. unattended-upgrades) закрывают известные уязвимости — самая дешёвая и эффективная мера.
  • SSH-ключи вместо паролей делают перебор бессмысленным; после проверки ключа отключайте PasswordAuthentication.
  • Запретите вход root по SSH (PermitRootLogin no), работая под обычным пользователем с sudo.
  • Файрвол (ufw/firewalld) оставляет открытыми только нужные порты; SSH разрешайте до включения.
  • fail2ban блокирует переборщиков по логам; принцип минимальных привилегий ограничивает ущерб; ss -tulpn показывает, что реально слушает сеть.
Проверьте себя
1. В каком порядке безопаснее всего настраивать вход по SSH-ключам, чтобы не запереть себя снаружи?
AСразу отключить PasswordAuthentication, затем сгенерировать и скопировать ключ
BСгенерировать ключ, скопировать публичный ключ на сервер (ssh-copy-id), УБЕДИТЬСЯ что вход по ключу работает, и только потом отключать PasswordAuthentication
CОтключить вход root, перезагрузить сервер, затем создать ключ
DПорядок не важен, sshd сам всё подхватит
2. В выводе `ss -tulpn` вы видите строку с PostgreSQL, слушающим на `0.0.0.0:5432`. Почему это потенциальная проблема и что обычно делают?
A0.0.0.0 означает, что база слушает на всех интерфейсах и доступна из интернета; БД, которой не нужен внешний доступ, привязывают к 127.0.0.1 и/или закрывают файрволом
B0.0.0.0 — это локальный адрес, всё в порядке, ничего делать не нужно
CЭто значит, что PostgreSQL выключен; нужно его запустить
DПорт 5432 запрещён в Linux, его надо сменить на 22