ГлавнаяБлогУкрепляем безопасность Kad-DHT: защита от Eclipse-атак
Алгоритмы

Укрепляем безопасность Kad-DHT: защита от Eclipse-атак

Разбираем, как усилить безопасность Kad-DHT против Eclipse-атак: IP-разнообразие подсетей, борьба с флаки-тестами и практические выводы для вашего кода.

Al
Редакция Algolitalgolit.ru
7 мин чтения1 августа 2026 г.

Зачем читать эту статью

Вы когда-нибудь задумывались, как децентрализованные сети защищаются от атак, когда злоумышленник окружает ваш узел своими подконтрольными нодами? Это называется Eclipse-атака, и она может полностью отрезать вас от сети. В этой статье мы разберём, как мы укрепляем Kademlia DHT в py-libp2p, внедряя IP-разнообразие подсетей, и как боремся с флаки-тестами, которые мешают разработке. Вы получите конкретные практические приёмы для повышения безопасности и стабильности ваших P2P-систем.

Проблема: Eclipse-атаки на Kademlia DHT

Kademlia — это распределённая хеш-таблица (DHT), используемая во многих P2P-сетях. Она хранит информацию о других узлах в k-корзинах (k-buckets). Если атакующий контролирует множество узлов в одной подсети, он может заполнить ваши k-корзины своими узлами, изолировав вас от честной сети. Это называется Eclipse-атакой. Защита от неё критически важна для целостности сети.

Как работает Eclipse-атака

Представьте, что вы общаетесь только с соседями. Если все соседи — друзья злоумышленника, они могут передавать вам ложную информацию или блокировать доступ к реальным узлам. В DHT это означает, что ваши запросы на поиск данных будут обрабатываться только подконтрольными узлами, которые могут вернуть поддельные данные.

Решение: IP-разнообразие подсетей

Мы реализовали функцию, которая ограничивает количество узлов из одной IP-подсети в k-корзинах. Это делает атаку дороже: злоумышленнику придётся арендовать множество разных подсетей, что значительно увеличивает стоимость атаки.

Реализация в py-libp2p

В PR feat(kad_dht): enforce IP subnet diversity in k-buckets (#1383) мы добавили 226 строк логики. Основная идея — при добавлении нового узла в k-корзину проверять, сколько уже узлов из той же подсети. Если лимит превышен, узел не добавляется.

# Пример: проверка IP-разнообразия
from ipaddress import ip_network, ip_address

MAX_PER_SUBNET = 2  # максимум узлов из одной подсети

def is_allowed(peer_ip, subnet_count):
    """Проверяем, можно ли добавить узел"""
    return subnet_count.get(peer_ip, 0) < MAX_PER_SUBNET

# Использование
subnet_counts = {}  # словарь: подсеть -> количество узлов
peer_ip = '192.168.1.5'
subnet = ip_network(peer_ip + '/24', strict=False)
if is_allowed(str(subnet), subnet_counts):
    subnet_counts[str(subnet)] = subnet_counts.get(str(subnet), 0) + 1
    # добавляем узел в k-корзину
else:
    # отклоняем узел
    pass

Мы также отказались от рандомизированного выбора узлов при поиске, так как это не давало достаточной защиты. Более надёжный подход — строгое управление k-корзинами.

Борьба с флаки-тестами в асинхронном коде

Асинхронное программирование приносит не только скорость, но и проблемы с тестами. Флаки-тесты — это тесты, которые иногда проходят, иногда нет, из-за гонок (race conditions). Мы разобрали два таких случая.

Проблема 1: test_expiry_removal

Тест проверял удаление записей по истечении времени. Ошибка была в том, что фоновый поток очистки не успевал завершиться до проверки. Решение — использовать более точные ожидания и моки.

# Пример исправления: ожидание завершения фоновой задачи
import trio

async def test_expiry():
    cache = TimedCache(expiry=0.1)
    cache.add('key', 'value')
    await trio.sleep(0.2)  # ждём больше, чем таймер
    assert 'key' not in cache

Вместо trio.sleep с фиксированной задержкой лучше использовать trio.wait_all_tasks_blocked или явные события.

Проблема 2: test_gossip_gate_filters_peers

Второй тест касался Gossipsub — подписки распространяются асинхронно. Если тест проверяет состояние слишком рано, он падает. Решение — добавить ожидание распространения подписки.

async def test_gossip_gate():
    # ... настройка узлов
    await node1.subscribe('topic')
    # Ждём, пока подписка дойдёт до node2
    await trio.sleep(0.5)  # эвристика, лучше использовать события
    assert node2.has_subscription('topic')

Эти исправления не самые захватывающие, но они делают CI стабильным, что экономит часы времени.

Инструменты и окружение

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

Практический вывод

Если вы работаете с P2P-сетями, обязательно внедряйте IP-разнообразие подсетей, чтобы защититься от Eclipse-атак. Для асинхронных тестов используйте явные ожидания вместо sleep. Начните с проверки своих k-корзин на предмет концентрации узлов из одной подсети — это простой шаг к безопасности.

В следующей неделе я планирую довести до конца PR по IP-разнообразию и заняться новыми фичами. Следите за обновлениями!

#Kademlia DHT#Eclipse-атака#безопасность#py-libp2p#асинхронные тесты
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →