Коли говорять про безпеку сервера, найчастіше питають про фаєрвол, але спершу потрібно зрозуміти, що взагалі доступне ззовні. Служба може слухати порт і водночас бути недоступною з інтернету, а може бути відкритою з забутої причини. У статті — як побачити список портів, що слухають, зсередини, перевірити їх ззовні, розібрати типові знахідки та закрити зайве.
«Слухає» і «доступний ззовні» — не те саме
Служба слухає порт, коли прив'язана (bind) до адреси і чекає на з'єднання. Доступність ззовні залежить ще від адреси прив'язки, фаєрвола на сервері та мережевих правил перед ним. Якщо службу прив'язано до 127.0.0.1, з'єднатися з нею можна лише з самого сервера. Якщо до 0.0.0.0 — вона приймає з'єднання на всіх адресах, і захистити її від інтернету може лише фаєрвол. Основи портів і сокетів розібрано в статті порт, сокет і служба.
Дивимось зсередини: ss -tulpn
Команда ss із пакета iproute2 показує сокети. Ключі: -t — TCP, -u — UDP, -l — лише ті, що слухають, -p — процес, -n — числові адреси та порти. Щоб бачити назви чужих процесів, запускайте від root.
sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=812,fd=3))
tcp LISTEN 0 80 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=1044,fd=21))
tcp LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* users:(("nginx",pid=930,fd=6))
tcp LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=930,fd=7))
| Адреса в Local Address | Значення |
|---|---|
| 0.0.0.0 | Усі IPv4-адреси сервера; доступ обмежує лише фаєрвол |
| [::] | Усі IPv6-адреси сервера, те саме для IPv6 |
| 127.0.0.1 | Лише петля: підключитися можна тільки з цього ж сервера |
| 192.0.2.10 | Одна конкретна адреса сервера |
У прикладі SSH і MySQL прив'язані до 0.0.0.0, Nginx на порту 8080 — до 127.0.0.1, а на порту 80 слухає і на IPv6. Питання до такого списку одне: для кожного рядка з 0.0.0.0 чи [::] має бути пояснення, навіщо вона відкрита світу.
Дивимось ззовні
Остаточну картину видно лише з іншої машини: з домашнього комп'ютера чи іншого сервера. Скануйте виключно власні сервери. Утиліта nmap покаже стан портів, а nc — швидко перевірить один порт:
nmap -Pn -p 22,80,443,3306 203.0.113.10
nc -zv 203.0.113.10 3306
Стан open означає, що порт приймає з'єднання; closed — що хост відповідає, але служба не слухає; filtered — що пакети відкидаються фаєрволом. Розбіжність між ss і зовнішньою перевіркою — привід розібратися: або фаєрвол працює, або правила не застосувалися. Інші прийоми діагностики описано в статті діагностика мережі в Linux.
Типові знахідки
| Знахідка | Чим небезпечна | Що робити |
|---|---|---|
| База даних на 0.0.0.0 | Порт відкритий для підбору паролів і експлуатації вразливостей | Прив'язати до 127.0.0.1 |
| Панель на нестандартному порту | Зміна порту не ховає панель від сканерів | Закрити фаєрволом або винести за тунель |
| Забутий тестовий сервіс | Часто без паролів і оновлень | Зупинити й вимкнути з автозапуску |
| Порт Docker, опублікований назовні | Docker сам править правила iptables і може обійти правила фаєрвола | Публікувати як 127.0.0.1:порт |
Як закривати
Найкращий варіант — взагалі не відкривати порт: прив'язати службу до 127.0.0.1. Фаєрвол — другий рубіж, а не заміна. Типові параметри, після правки яких службу потрібно перезапустити:
bind-address = 127.0.0.1
listen_addresses = 'localhost'
bind 127.0.0.1
docker run -p 127.0.0.1:3306:3306 image
Рядки стосуються по порядку MySQL (розділ [mysqld]), PostgreSQL (postgresql.conf), Redis (redis.conf) і запуску контейнера Docker. Потім увімкніть фаєрвол із забороною вхідних за замовчуванням і дозвольте лише потрібне: налаштування показано в статті UFW для VPS. Перед вмиканням переконайтеся, що порт SSH дозволено, інакше ви втратите доступ.
Якщо до закритої служби все ж потрібен доступ, публікувати порт не обов'язково. Для бази підійде SSH-тунель: порт на вашому комп'ютері прокидається на 127.0.0.1 сервера. Для вебпанелей є Cloudflare Tunnel.
ssh -L 3307:127.0.0.1:3306 user@203.0.113.10
Поки тунель відкритий, підключайтеся клієнтом бази до 127.0.0.1:3307. Після будь-яких змін повторіть ss -tulpn і зовнішню перевірку: результат має збігатися із задумом.
Часті питання
Як дізнатися, які порти відкриті на моєму сервері?
Зсередини виконайте sudo ss -tulpn: команда покаже всі порти, що слухають, і процеси. Потім перевірте сервер ззовні з іншої машини через nmap або nc. Остаточною вважається зовнішня перевірка, бо лише вона враховує фаєрвол і мережеві правила, а ss показує тільки те, що слухає сама система.
Що означає 0.0.0.0 у виводі ss?
Це означає, що служба приймає з'єднання на всіх IPv4-адресах сервера, тобто потенційно з інтернету. Запис [::] означає те саме для IPv6. Адреса 127.0.0.1 обмежує доступ самим сервером. Для баз даних і службових сервісів потрібен саме 127.0.0.1, якщо їм не потрібні зовнішні клієнти.
Чи достатньо фаєрвола, щоб закрити зайві порти?
Фаєрвол необхідний, але надійніше усунути причину: служба, прив'язана до 127.0.0.1, недоступна ззовні навіть за помилки в правилах. Фаєрвол варто розглядати як другий шар. Зважайте й на контейнери: Docker сам змінює правила iptables, тому опублікований порт може виявитися відкритим всупереч налаштуванням UFW.
Як підключитися до закритої бази даних з мого комп'ютера?
Використовуйте SSH-тунель: команда ssh із ключем -L прокидає локальний порт вашого комп'ютера на 127.0.0.1 сервера. Клієнт бази потім підключається до локального порту. Так порт бази лишається закритим для інтернету, а доступ отримують лише ті, хто має SSH-доступ до сервера.