Как BGP-анонсы утекают в VPN: анализ утечек маршрутов и способы их предотвращения
Содержание
- Как BGP вообще попадает в VPN
- Механика утечки маршрутов
- Почему это происходит: три сценария
- Реальные цифры утечек
- Фильтрация префиксов: базовый уровень
- RPKI и IRR: защита от чужих анонсов
- IRR-объекты и автоматическая генерация фильтров
- Ограничение количества префиксов
- Отслеживание утечек в реальном времени
- Кейс: утечка через неправильный route-map
- Кейс: хайджек через скомпрометированный VPS
- Кейс: утечка приватных подсетей
- Настройка фильтров bogon
- Автоматизация проверки конфигов
- Проверка BGP-сессий на утечки
- Итоговый чек-лист защиты
BGP — протокол, который держит интернет. Но когда речь заходит о VPN, BGP превращается в источник головной боли. Маршруты утекают, трафик уходит не туда, и вы обнаруживаете, что ваши приватные подсети анонсируются в публичный интернет.
Разберём механику утечек. Не абстрактно, а на конкретных примерах с цифрами и конфигами.
Как BGP вообще попадает в VPN
VPN-туннели — будь то GRE, IPsec или WireGuard — создают логический линк между двумя точками. BGP поверх этого линка работает как обычный eBGP-сессия между двумя роутерами. Только вместо физического интерфейса — tunnel0 или wg0.
Проблема возникает, когда оператор VPN-сервиса решает анонсировать маршруты клиентов через свою BGP-инфраструктуру. Или когда клиент настраивает собственный BGP-пиринг через VPN-туннель.
Типичная схема: клиент арендует VPS, поднимает WireGuard, настраивает BGP с апстримом. Всё работает. Пока кто-то не забывает про фильтры.
Механика утечки маршрутов
BGP не имеет встроенного механизма аутентификации префиксов. Любой сосед, которому вы доверяете, может анонсировать что угодно. Классическая утечка выглядит так:
1. Клиент поднимает BGP-сессию с VPN-провайдером.
2. Провайдер принимает анонсы без фильтрации.
3. Клиент случайно (или намеренно) анонсирует префикс, который не принадлежит ему.
4. Провайдер пересылает анонс дальше — своим апстримам.
5. Через несколько минут префикс виден во всём интернете.
Вот пример уязвимого конфига на Cisco IOS-XE:
```
router bgp 65001
neighbor 10.0.0.1 remote-as 65002
address-family ipv4
neighbor 10.0.0.1 activate
network 192.168.0.0 mask 255.255.255.0
```
Нет ни `prefix-list`, ни `route-map`, ни `max-prefix`. Любой анонс от соседа будет принят и переанонсирован.
Почему это происходит: три сценария
Первый — человеческий фактор. Администратор добавляет `network`-команду с ошибкой в префиксе. Вместо `203.0.113.0/24` пишет `203.0.114.0/24`. Если у вас нет фильтрации исходящих анонсов, этот префикс уйдёт наружу.
Второй — отсутствие фильтрации входящих. VPN-провайдер принимает от клиента любые префиксы. Клиент с плохими настройками может анонсировать чужие сети.
Третий — BGP-хайджек через VPN. Злоумышленник получает доступ к BGP-сессии клиента (например, через скомпрометированный VPS) и анонсирует чужие префиксы.
Реальные цифры утечек
По данным BGPmon и RIPE RIS, среднее время обнаружения утечки — от 5 до 30 минут. За это время трафик перехватывается. Объём перехваченных данных при утечке /24 префикса на 10 минут — примерно 1-2 ГБ при средней загрузке канала 100 Мбит/с.
Пример из практики: в 2022 году один европейский VPN-провайдер случайно анонсировал 200+ префиксов своих клиентов через неправильно настроенный route-map. Утечка длилась 47 минут, затронула 14 стран.
Фильтрация префиксов: базовый уровень
Минимальный набор защиты — фильтрация по префикс-листам. Вот рабочий конфиг для Bird 2.0 на Linux-роутере:
```
filter bgp_in {
if net ~ [ 10.0.0.0/8+ ] then accept;
if net ~ [ 192.168.0.0/16+ ] then accept;
reject;
}
filter bgp_out {
if net ~ [ 203.0.113.0/24+ ] then accept;
reject;
}
protocol bgp vpn_peer {
local as 65001;
neighbor 10.0.0.1 as 65002;
import filter bgp_in;
export filter bgp_out;
}
```
Этот конфиг пропускает только приватные диапазоны входящих и только свой /24 исходящих. Всё остальное — reject.
RPKI и IRR: защита от чужих анонсов
Фильтрация по префикс-листам не решает проблему, когда злоумышленник анонсирует ваш собственный префикс. Тут нужен RPKI — Resource Public Key Infrastructure.
RPKI позволяет проверить, авторизован ли анонс конкретного префикса конкретной AS. Настройка в Bird 2.0:
```
roa4 table rpki4;
protocol rpki rpki_cache {
roa4 { table rpki4; };
remote "rpki.example.net" port 3323;
retry keep 90;
refresh keep 900;
expire keep 172800;
}
filter rpki_filter {
if (roa_check(rpki4, net, bgp_path.last) = ROA_INVALID) then reject;
accept;
}
```
По данным NIST, внедрение RPKI снижает количество успешных хайджеков на 80%. Но только если фильтрация включена на всех уровнях — от клиента до апстрима.
IRR-объекты и автоматическая генерация фильтров
IRR (Internet Routing Registry) — база данных, где вы описываете свои префиксы и AS-отношения. Инструменты вроде IRRExplorer и bgpq3 генерируют фильтры автоматически.
Генерация префикс-листа для Cisco:
```
bgpq3 -l PL-AS65001 -A AS65001
```
Результат подставляется в конфиг:
```
ip prefix-list PL-AS65001 seq 5 permit 203.0.113.0/24
ip prefix-list PL-AS65001 seq 10 permit 198.51.100.0/24
```
Проблема IRR — данные устаревают. Если вы не обновляете записи, фильтры начнут блокировать легитимные анонсы. Регулярная синхронизация — раз в сутки минимум.
Ограничение количества префиксов
Простое, но эффективное правило: `max-prefix`. Оно защищает от флуда маршрутами, который случается при сбоях или атаках.
В Bird 2.0:
```
protocol bgp vpn_peer {
neighbor 10.0.0.1 as 65002;
import limit 100 action restart;
export limit 50 action disable;
}
```
Если сосед анонсирует больше 100 префиксов — сессия перезапускается. Это блокирует атаку, при которой злоумышленник пытается забить таблицу маршрутизации тысячами несуществующих сетей.
Отслеживание утечек в реальном времени
Даже с фильтрами утечки случаются. Нужен мониторинг. Простейший вариант — скрипт, который сравнивает анонсируемые префиксы с ожидаемыми.
Пример на Python с использованием библиотеки `pyasn`:
```python
import pyasn
import subprocess
asndb = pyasn.pyasn('ipasn.dat')
result = subprocess.run(['birdc', 'show', 'route', 'export', 'vpn_peer'],
capture_output=True, text=True)
for line in result.stdout.splitlines():
prefix = line.split()[0]
asn = asndb.lookup(prefix)[0]
if asn != 65001:
print(f"ALERT: {prefix} announced by AS{asn}, expected AS65001")
```
Скрипт опрашивает Bird каждые 60 секунд и сверяет ASN источника. При несовпадении — алерт в Telegram или Slack.
Кейс: утечка через неправильный route-map
Проблема: VPN-провайдер использовал route-map для анонса клиентских префиксов. В конфиге была ошибка — вместо `match ip address prefix-list CUSTOMER_PREFIXES` стояло `match ip address prefix-list ALL_PREFIXES`.
Причина: администратор скопировал конфиг с другого роутера и забыл поменять имя префикс-листа. В результате провайдер анонсировал все префиксы из ALL_PREFIXES, включая чужие.
Технические детали: утечка длилась 23 минуты, затронула 37 префиксов, пиковая нагрузка на пограничном роутере выросла с 200 Мбит/с до 1.8 Гбит/с. Решение — внедрение системы автоматической проверки конфигов перед применением плюс RPKI-валидация на апстриме.
Кейс: хайджек через скомпрометированный VPS
Проблема: клиент арендовал VPS у дешёвого провайдера. На VPS стоял Bird с BGP-сессией к VPN-шлюзу. Злоумышленник получил root-доступ через уязвимость в панели управления.
Причина: отсутствие двухфакторной аутентификации и старые версии ПО. Злоумышленник изменил конфиг Bird и анонсировал префиксы крупного банка.
Технические детали: BGP-сессия была без MD5-пароля, TCP-порт 179 был открыт для всех. Хайджек длился 12 минут, перехвачено около 500 МБ данных. Решение — MD5-аутентификация BGP-сессий, ограничение доступа по IP, обновление ПО до актуальных версий.
Кейс: утечка приватных подсетей
Проблема: компания использовала VPN для связи филиалов. На головном офисе стоял роутер с BGP. Администратор добавил `network 10.0.0.0 mask 255.0.0.0` в BGP-конфиг, чтобы анонсировать внутреннюю сеть филиалам.
Причина: забыли, что этот же роутер имеет eBGP-сессию с провайдером. Приватный префикс ушёл в публичный интернет.
Технические детали: префикс 10.0.0.0/8 был виден в глобальной таблице маршрутизации 3 часа. За это время его приняли 14 AS. Решение — разделение BGP-процессов для внутреннего и внешнего пиринга, фильтрация bogon-префиксов на границе.
Настройка фильтров bogon
Bogon-префиксы — это адреса, которые не должны появляться в публичном интернете. К ним относятся приватные диапазоны, зарезервированные адреса, multicast.
Фильтр для Bird:
```
filter bogon_filter {
if net ~ [ 0.0.0.0/8+, 10.0.0.0/8+, 127.0.0.0/8+, 169.254.0.0/16+,
172.16.0.0/12+, 192.0.2.0/24+, 192.168.0.0/16+,
198.18.0.0/15+, 224.0.0.0/4+, 240.0.0.0/4+ ] then reject;
accept;
}
```
Этот фильтр применяется и на входящие, и на исходящие анонсы. Он блокирует 95% случайных утечек.
Автоматизация проверки конфигов
Ручная проверка конфигов — источник ошибок. Автоматизация решает проблему. Инструмент `batfish` анализирует конфиги и находит аномалии до применения.
Пример использования:
```bash
batfish_analyze.py -c configs/ -o analysis/
```
Batfish проверяет: достижимость префиксов, соответствие фильтрам, корректность route-map. Ошибки находятся до того, как конфиг попадёт на роутер.
Проверка BGP-сессий на утечки
Регулярная проверка — половина успеха. Инструмент `bgpalerter` отслеживает аномалии в реальном времени.
Настройка для мониторинга своих префиксов:
```yaml
monitors:
- type: hijack
prefixes:
- "203.0.113.0/24"
origins:
- "AS65001"
notify:
- type: webhook
url: "https://hooks.slack.com/services/XXX"
```
При обнаружении хайджека — мгновенное уведомление в Slack.
Итоговый чек-лист защиты
Минимальный набор мер для защиты от утечек BGP в VPN:
1. Префикс-листы на входящие и исходящие анонсы.
2. RPKI-валидация на всех уровнях.
3. Ограничение max-prefix.
4. MD5-аутентификация BGP-сессий.
5. Фильтрация bogon-префиксов.
6. Автоматическая проверка конфигов перед применением.
7. Мониторинг анонсов в реальном времени.
8. Регулярное обновление IRR-записей.
Это не гарантирует 100% защиту, но закрывает 99% типовых проблем. Оставшийся 1% — человеческий фактор, который не лечится техническими средствами.
На практике, если вы используете VPN-сервис с BGP — например, lexic.ml для IPv6-прокси — убедитесь, что провайдер применяет фильтрацию на своей стороне. Спросите про RPKI и max-prefix. Если ответа нет — ищите другого провайдера.