Network hardening
Default-deny в сети блокирует всё и разрешает только именованные потоки — включая egress, направление, о котором забывают чаще всего. Вместе с сегментацией и убийством протоколов открытым текстом это превращает захваченную машину из плацдарма в тупик.
Атакующий пробивает один воркер ресайза картинок через CVE в зависимости. Машина внутренняя — публичного входа нет, никто не паникует. За девяносто секунд она подключается наружу к 45.9.x.x:443, тянет вторую стадию пейлоада, сканирует плоскую сеть 10.0.0.0/8, находит на соседнем хосте Redis без аутентификации и выгружает сессионные токены. Каждый из этих шагов пересёк сетевую границу, которая это разрешила. Входной фаервол, на котором все были помешаны, не сработал ни разу: воркер инициировал всё сам. Вот цена незакалённой сети — не взлом одной машины, а свободное перемещение после него.
К концу урока ты будешь знать, почему default-deny обязан покрывать egress, как сегментация сдерживает радиус поражения и почему убийство протоколов открытым текстом не подлежит обсуждению.
Default-deny — единственная масштабируемая позиция фаервола
Набор правил фаервола — это политика о том, что может происходить на проводе. Написать её можно ровно двумя способами. Default-allow разрешает всё и перечисляет, что блокировать, — ты выписываешь атаки, о которых подумал, и каждая, о которой не подумал, проходит. Default-deny дропает всё и перечисляет, что разрешить, — ты выписываешь потоки, которые приложению реально нужны, а всё остальное, известное и неизвестное, запрещено отсутствием правила.
Вся суть в этой асимметрии. Список default-allow — это блок-лист, а блок-лист полон ровно настолько, насколько богато было твоё воображение в день написания. Список default-deny — это allow-лист, и он отказывает в закрытую: новый сервис, новый порт, забытый отладочный эндпоинт, свежий CVE, открывший неожиданный слушатель, — ничто из этого не заработает, пока кто-то осознанно не напишет правило. Это тот же рефлекс deny-by-default, что управляет авторизацией в приложении, применённый слоем ниже — на сети. CIS Benchmarks и NIST SP 800-123 делают финальное правило неявного запрета базовой нормой именно поэтому: оно превращает «а мы не забыли это заблокировать?» в «а мы не забыли это разрешить?», и на второй вопрос рецензент действительно может ответить, просто прочитав набор правил.
Причина, по которой команды всё ещё отгружают default-allow, операционная, а не архитектурная: deny-by-default громко ломает всё, пока каждый легитимный поток не перечислен, а это перечисление — настоящая работа. Но эта боль и есть фича — она заставляет тебя знать собственный трафик.
Egress — половина фаервола, о которой все забывают
Зайди в большинство сетей: входные правила жёсткие, а egress-правила — одна строка: allow all outbound. Эта одна строка и сделала сценарий из Hook возможным. Почти каждая современная цепочка атаки зависит от исходящих соединений, которые разрешил защитник: подтянуть вторую стадию пейлоада, маячить на command-and-control сервер и выгрузить украденные данные обратно наружу. Фаервол только-на-входе — это дверь с засовом снаружи и снятой внутренней ручкой: он не пускает войти и ничего не делает с тем, кто уже внутри и выходит с серебром.
Egress-фильтрация применяет default-deny к исходящему направлению: воркер может инициировать соединения только к тем конкретным адресам, которые нужны для его работы. Платёжному воркеру, который общается с одним банковским API и твоей базой, незачем открывать TLS-соединение к произвольному IP в интернете — поэтому он не может, и в момент попытки она запрещается и логируется, что часто и есть твой самый ранний сигнал компрометации. Самое ценное egress-правило на облачном хосте — заблокировать исходящий доступ к metadata-эндпоинту инстанса (169.254.169.254) для всего, чему он не нужен: именно этот link-local адрес превращает SSRF или захваченный контейнер в украденные облачные учётки.
Сегментация решает радиус поражения
Плоская сеть — один большой 10.0.0.0/8, где каждый хост достаёт любой другой по любому порту, — означает, что радиус поражения любой компрометации — всё хозяйство целиком. Сегментация разбивает сеть на зоны (подсети, VLAN, security groups, Kubernetes NetworkPolicies, авторизация service-mesh) и навязывает default-deny между ними. East-west трафик — сервер-к-серверу, направление, по которому идёт латеральное движение, — теперь обязан пересечь границу, которая по умолчанию говорит «нет».
Выигрыш конкретен: помести слой базы в собственный сегмент, до которого добирается только слой приложения по порту 5432, — и захваченная фронтовая веб-машина не сможет тронуть базу напрямую, хотя обе живут «в сети». Помести каждый микросервис под свою политику — и захваченный ресайзер картинок не сможет сканировать соседей. Классический худший случай — одна машина скомпрометирована, а затем неаутентифицированные внутренние сервисы (Redis, Elasticsearch, админ-панель) достижимы плоско по всей подсети — это ровно то, что убирает сегментация. Ты здесь не предотвращаешь первый взлом; ты делаешь так, чтобы первый взлом был и последней машиной.
▸Почему это работает
Почему «у нас есть периметровый фаервол» — недостаточно? Потому что периметр — это одна яичная скорлупа: твёрдая снаружи, мягкая везде внутри. В момент, когда одна вещь внутри скомпрометирована — фишнутый ноутбук, уязвимая зависимость, утёкшая учётка, — плоская внутренность даёт нулевое трение латеральному движению. Сегментация плюс внутренний default-deny — это то, что операционализирует zero trust: перестать считать «внутри сети» границей доверия и аутентифицировать и авторизовывать каждый хоп так, будто он пришёл из открытого интернета. Периметр всё ещё важен; ему просто больше не позволено быть единственным контролем.
Убийство протоколов открытым текстом
Каждый протокол открытым текстом в твоей сети — это утечка учёток и вектор подмены, ждущий любого, кто видит провод, — а в общей или облачной сети «видеть провод» дешевле, чем думают команды. Правило закалки прямое: никакого открытого текста для всего, что несёт учётки, данные или управление. Замени незашифрованный протокол его аутентифицированным шифрованным преемником, а потом выключи старый на сервере — не просто «предпочитай» новый, потому что протокол, который ещё слушает, — это протокол, на который атакующий может тебя даунгрейднуть.
| Убить это | Порт | Чем опасно | Вместо этого |
|---|---|---|---|
| Telnet | 23 | Логин и каждое нажатие клавиши открытым текстом | SSH (22), аутентификация по ключам |
| FTP | 21 | Учётки и файлы открытым текстом | SFTP / FTPS |
| HTTP (внутренний) | 80 | Токены, куки, данные читаемы и подменяемы | HTTPS / mTLS, HSTS |
| SNMP v1/v2c | 161 | Community string — это пароль открытым текстом | SNMPv3 (auth + privacy) |
| LDAP | 389 | Bind-учётки открытым текстом | LDAPS / StartTLS |
| TLS 1.0 / 1.1, SSLv3 | — | Заведомо сломанные шифры, даунгрейдятся | TLS 1.2+ (лучше 1.3) |
«Внутренний HTTP — нормально, он никогда не покидает нашу сеть» — это опасная полуправда: как только ты признаёшь, что атакующий уже может быть внутри сети (вся посылка сегментации), внутренний открытый текст ровно так же открыт, как внешний. Шифруй и east-west трафик тоже — взаимный TLS между сервисами и есть ответ service-mesh, — чтобы плацдарм на одной машине не вручал атакующему отвод на трафик всех остальных.
Платёжный сервис работает в плоском облачном VPC с egress allow-all. Ты можешь отгрузить одно изменение за спринт, чтобы максимально сократить радиус поражения при компрометации этого сервиса. Выбери ход с наибольшим рычагом.
Почему фаервол default-deny (allow-лист) фундаментально безопаснее, чем default-allow (блок-лист)?
На сервисе всё ещё включён TLS 1.0 «для старого клиента» рядом с TLS 1.3. Почему оставлять старую версию слушающей — реальный риск, а не просто легаси-мусор?
Упорядочь эти ходы закалки сети от самого широкого сокращения радиуса поражения к самому локальному, как ты бы их вводил поэтапно:
- 1 Default-deny на входе И на egress как базовая норма фаервола (разрешать только именованные потоки)
- 2 Сегментировать сеть на зоны с default-deny между ними (сдержать east-west)
- 3 Запереть облачный metadata-эндпоинт и per-service egress-адреса
- 4 Выключить протоколы открытым текстом и слабый TLS на слушателях каждого сервиса
- 01Объясни, почему egress-фильтрация важна не меньше входной, и назови самое ценное egress-правило на облачном хосте.
- 02Как сегментация и убийство протоколов открытым текстом вместе сдерживают компрометацию одной машины и почему «внутренний HTTP — нормально» неверно?
Закалка сети — это дисциплина решать радиус поражения компрометации до того, как она случится. Фундамент — default-deny: фаервол, который дропает всё и разрешает только именованные потоки, нужные приложению, так что неизвестные и будущие атаки запрещены отсутствием правила, а не проскальзывают мимо неполного блок-листа. Критически, default-deny обязан покрывать egress, а не только вход — пост-компрометационное движение (вторые стадии пейлоада, маячение на C2, выгрузка данных, кража облачных учёток с 169.254.169.254) всё исходящее, поэтому сплошное правило «allow all outbound» — та брешь, которую большинство команд оставляют открытой. Сегментация навязывает default-deny между зонами, так что east-west латеральное движение упирается в границу, превращая одну захваченную машину в тупик вместо плацдарма по плоской сети. И каждый протокол открытым текстом — Telnet, FTP, внутренний HTTP, SNMPv1/2c, голый LDAP — плюс слабые версии TLS нужно выключить на сервере, а не просто пометить устаревшими, ведь на протокол, который ещё слушает, можно даунгрейднуть. Теперь, видя сервис с egress allow-all на плоской сети, твой первый вопрос: когда эту машину захватят, сможет ли она достать что-то, кроме двух адресов, которые ей реально нужны?
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.