Сети для самых маленьких. Часть 19: IPsec и IKEv2

Всё, что мы разбирали до сих пор, ходило по сети открытым текстом: заголовки, данные, пароли в PAP из четвёртой части, запросы DNS. Защиту мы встречали только выше транспорта — TLS, протокол шифрования внутри TCP-соединения, на котором работает HTTPS: он защищает данные одного приложения, и только если приложение его использует. IPsec делает защиту на сетевом уровне: шифрует и подписывает IP-пакеты целиком, так что приложения о ней не знают, а защищённым оказывается всё — любой протокол, любой порт. На IPsec построены туннели между офисами, подключение сотрудников к корпоративной сети и, как увидим в следующей части, большинство «VPN» в настройках телефона.

IPsec — это два слоя. IPsec в узком смысле — формат защищённых пакетов и правила их обработки: что шифровать, каким ключом, как проверять. IKE — Internet Key Exchange, протокол, по которому две стороны договариваются об алгоритмах, проверяют друг друга и вырабатывают ключи для первого слоя. Разберём снизу вверх.


Что защищает IPsec и как

Два протокола, оба — Next Header / Protocol в заголовке IP:

  • ESP (Encapsulating Security Payload, протокол 50) — шифрование и проверка целостности. Используется практически всегда.
  • AH (Authentication Header, протокол 51) — только целостность и подлинность, без шифрования, причём подпись покрывает и заголовок IP. Из-за этого AH несовместим с NAT, который заголовок меняет, и сегодня почти не встречается: ESP с проверкой целостности делает всё то же, кроме защиты самого IP-заголовка, которая никому не нужна.

И два режима, которые решают, что именно заворачивается:

 исходный пакет:        ┌─────────┬───────────────────────┐
                        │ IP      │ TCP + данные          │
                        └─────────┴───────────────────────┘

 транспортный режим:    ┌─────────┬─────┬────────────────────────┬───────┬─────┐
                        │ IP      │ ESP │ TCP + данные           │ ESP   │ ICV │
                        │ (тот же)│ hdr │ ░░░ зашифровано ░░░░░░ │ trail │     │
                        └─────────┴─────┴────────────────────────┴───────┴─────┘

 туннельный режим:      ┌─────────┬─────┬────────┬───────────────┬───────┬─────┐
                        │ новый   │ ESP │ IP     │ TCP + данные  │ ESP   │ ICV │
                        │ IP      │ hdr │ ░░░░░░░ зашифровано ░░░░░░░░░░ │     │
                        └─────────┴─────┴────────┴───────────────┴───────┴─────┘

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

Пакет ESP

 ┌───────────────────┐
 │ SPI (4)           │  какой SA: по нему получатель находит ключи и алгоритмы
 │ Sequence (4)      │  номер пакета, растёт на 1: защита от повторов
 ├───────────────────┤
 │ IV                │  вектор инициализации для шифра
 │ данные ░░░░░░░░░░ │  зашифровано: исходный пакет (туннель) или сегмент (транспорт)
 │ padding ░░░░░░░░░ │  выравнивание до блока шифра
 │ pad len │ next hdr│  next header: 4 = IPv4 внутри, 41 = IPv6, 6 = TCP (транспорт)
 ├───────────────────┤
 │ ICV               │  код целостности: подпись всего выше ключом целостности
 └───────────────────┘

Получатель: по адресу назначения и SPI находит SA (ниже), проверяет, что Sequence ещё не видели (скользящее окно, обычно 64 или больше номеров), проверяет ICV ключом целостности, расшифровывает, читает next header в самом конце и узнаёт, что внутри — IPv4-пакет, который надо маршрутизировать дальше, или сегмент TCP для самого себя. Порядок важен: сначала целостность, потом расшифровка, чтобы не тратить время на подделку и не давать атакующему скармливать шифру мусор.

Алгоритмы: сегодня это AES-GCM (шифрование и целостность одним ключом, ICV 16 байт) или ChaCha20-Poly1305; старая связка — AES-CBC плюс HMAC-SHA256. 3DES, MD5, SHA1 — в списке «не использовать».

Накладные расходы туннельного режима с AES-GCM — около 50–60 байт на пакет (20 новый IP, 8 ESP, 8 IV, 16 ICV, выравнивание), плюс 8, если ESP в UDP. Поэтому у туннеля MTU 1400–1440, и MSS clamping из восьмой части в правилах для туннелей стоит почти всегда.

SA, SPI, SPD

Security Association — одностороннее соглашение «между A и B, для пакетов с таким SPI, такой алгоритм, такие ключи, такой режим, срок жизни столько-то секунд или байт». Одностороннее — значит, на каждое направление своя SA, и у туннеля их пара. SPI (32 бита) — номер, который получатель выбирает сам при создании SA, и отправитель ставит его в заголовок ESP; так одна машина различает сотни туннелей к ней.

Хранятся SA в SAD (базе SA). Рядом — SPD, база политик: правила «трафик с такими адресами, протоколом, портами — защищать такой SA / пропускать как есть / отбрасывать». Селекторы политик — это и есть то, что принято называть «какие сети ходят через туннель». Когда пакет уходит из машины, стек сверяет его с SPD; если политика «защищать», а SA ещё нет, стек просит IKE её создать и держит пакет, пока та не появится.

В Linux это подсистема xfrm, и всё перечисленное видно:

$ sudo ip xfrm state                     # SAD
src 198.51.100.2 dst 203.0.113.5
	proto esp spi 0xc1a2b3d4 reqid 1 mode tunnel
	replay-window 32 flag af-unspec
	aead rfc4106(gcm(aes)) 0x... 128
	anti-replay context: seq 0x0, oseq 0x1a, bitmap 0x00000000
src 203.0.113.5 dst 198.51.100.2
	proto esp spi 0x9e8f7a6b reqid 1 mode tunnel
	...

$ sudo ip xfrm policy                    # SPD
src 192.168.1.0/24 dst 10.0.0.0/24
	dir out priority 375423
	tmpl src 198.51.100.2 dst 203.0.113.5
		proto esp reqid 1 mode tunnel
src 10.0.0.0/24 dst 192.168.1.0/24
	dir in priority 375423
	...

Две SA с разными SPI на два направления, политика «из 192.168.1.0/24 в 10.0.0.0/24 — в туннель между шлюзами», счётчик oseq — сколько пакетов ушло.

Ключи в SA откуда-то взялись. Можно вписать их руками (ip xfrm state add … key 0x…), и это полезно, чтобы понять механику, но в жизни так не делают: ключи должны быть случайными, меняться, и обе стороны должны проверить друг друга. Это работа IKE.


IKEv2

IKEv2 (RFC 7296) — протокол поверх UDP 500 (и 4500, об этом ниже), по которому стороны:

  1. договариваются об алгоритмах и вырабатывают общий секрет по Диффи-Хеллману;
  2. проверяют подлинность друг друга;
  3. создают SA для ESP (в терминах IKE — Child SA) и потом пересоздают их по сроку.

Первая версия, IKEv1 1998 года, делала то же самое за шесть-девять сообщений в двух фазах с разными режимами и не умела ни NAT, ни EAP, ни смену адреса без дополнений; IKEv2 всё это встроил и уложил в четыре сообщения. IKEv1 жив в старом оборудовании, но новые туннели на нём не строят.

IKE_SA_INIT: договориться и обменяться ключами

   инициатор                                                             ответчик
     │                                                                      │
     ├── IKE_SA_INIT ──────────────────────────────────────────────────────►│
     │   SAi1: предложения (шифр, PRF, целостность, группа DH)              │
     │   KEi: открытое значение DH, Ni: случайное число                     │
     │   [NAT_DETECTION_*: хеши своих адреса и порта]                       │
     │                                                                      │
     │◄── IKE_SA_INIT ──────────────────────────────────────────────────────┤
     │   SAr1: выбранное предложение, KEr, Nr, [CERTREQ], [NAT_DETECTION_*] │
     │                                                                      │
     │  обе стороны: SKEYSEED = prf(Ni | Nr, g^ir)                          │
     │  из него SK_d, SK_ai, SK_ar, SK_ei, SK_er, SK_pi, SK_pr              │
     │  дальше всё шифруется и подписывается                                │

Два сообщения открытым текстом. Инициатор перечисляет, что умеет (например: AES-GCM-256, PRF HMAC-SHA256, DH группа 19 — эллиптическая кривая P-256, или 14 — modp2048, или 31 — Curve25519), прилагает свою половину обмена Диффи-Хеллмана и случайное число. Ответчик выбирает один набор и прилагает свои. После этого у обеих сторон есть общий секрет g^ir, которого не было в эфире, и из него с помощью PRF (псевдослучайной функции на основе HMAC) выводится семь ключей: для вывода дальнейших ключей (SK_d), для целостности и шифрования IKE-сообщений в каждую сторону (SK_a*, SK_e*) и для аутентификации (SK_p*).

Защита от затопления: ответчик, видя слишком много незавершённых обменов, может вместо ответа прислать COOKIE и потребовать повторить запрос с ним — состояние он до этого не заводит, как SYN cookies в TCP.

Ключевое свойство: пока никто никого не проверил. Общий секрет есть и с самозванцем, стоящим посередине. Проверка — следующий шаг.

IKE_AUTH: доказать, кто ты, и создать первую Child SA

   инициатор                                                         ответчик
     │                                                                      │
     ├── IKE_AUTH (зашифровано SK_ei) ─────────────────────────────────────►│
     │   IDi: кто я (адрес, FQDN, e-mail, DN сертификата)                   │
     │   [CERT]: мой сертификат                                             │
     │   AUTH: подпись первого моего сообщения + Nr + prf(SK_pi, IDi)       │
     │   SAi2: предложения для ESP, TSi, TSr: селекторы трафика             │
     │   [CP: дай мне адрес и DNS]                                          │
     │                                                                      │
     │◄── IKE_AUTH (зашифровано SK_er) ─────────────────────────────────────┤
     │   IDr, [CERT], AUTH: подпись своего первого сообщения + Ni + …       │
     │   SAr2, TSi, TSr (возможно, суженные), [CP: адрес, DNS]              │
     │                                                                      │
     │  IKE SA установлена, первая пара Child SA (ESP) установлена          │

AUTH — то, что связывает ключи с личностью. Каждая сторона подписывает своё первое сообщение IKE_SA_INIT (то, что ушло открытым текстом), чужое случайное число и хеш своего идентификатора. Самозванец посередине подменил бы значения DH в первом сообщении, и подпись не сошлась бы. Чем подписывают:

  • PSK, общий секрет: AUTH = prf(prf(PSK, «Key Pad for IKEv2»), данные). Просто, удобно между двумя шлюзами, но одна строка на обе стороны, которую нужно как-то передать и периодически менять.
  • Сертификаты: подпись закрытым ключом RSA или ECDSA, сертификат в CERT, доверие через общий удостоверяющий центр. Стандарт для шлюз-шлюз в организациях и обязателен для сервера удалённого доступа: клиенты Windows, iOS, Android требуют у сервера сертификат с именем, совпадающим с адресом подключения.
  • EAP для удалённого доступа: инициатор не присылает AUTH в первом IKE_AUTH, и обмен растягивается на несколько пар сообщений, внутри которых идёт EAP — тот самый протокол запросов-ответов из третьей части про Wi-Fi: EAP-MSCHAPv2 (логин и пароль, проверяется у сервера или через RADIUS, протокол, которым сетевое оборудование спрашивает у центральной базы, пускать ли пользователя) или EAP-TLS (сертификат пользователя). По итогам EAP обе стороны получают ключ MSK, и последняя пара IKE_AUTH несёт AUTH, вычисленный с ним. Сервер при этом всё равно подтверждает себя сертификатом.

В том же обмене создаётся первая Child SA — пара SA для ESP, по предложению SAi2 (шифр для ESP, может отличаться от IKE), и селекторы трафика TSi/TSr: инициатор говорит «я хочу защищать трафик от 192.168.1.0/24 к 10.0.0.0/24», ответчик соглашается или сужает до того, что разрешено ему. Сужение — частая причина «туннель поднялся, а пинг не идёт»: селекторы на двух концах не совпали, и SA создалась для пересечения, куда ваш трафик не попадает.

CP, configuration payload, — для удалённого доступа: клиент просит внутренний адрес, DNS, домен, и сервер их выдаёт, как DHCP, но внутри IKE. Так ноутбук получает 10.0.5.17 «внутри» корпоративной сети.

CREATE_CHILD_SA и INFORMATIONAL

Дальше IKE SA живёт долго (часы) и служит защищённым каналом для управления:

  • CREATE_CHILD_SA — создать ещё одну пару ESP SA (для другого набора селекторов) или пересоздать существующую по истечении срока — rekey. Ключи ESP живут час или гигабайты и меняются незаметно для трафика: новая SA создаётся до того, как удалена старая. При желании в rekey включают новый обмен DH (PFS, perfect forward secrecy): компрометация ключа IKE не раскроет прошлые ESP-ключи.
  • INFORMATIONAL — удаление SA, уведомления и две важные вещи. DPD (dead peer detection): пустое INFORMATIONAL, на которое другая сторона обязана ответить; нет ответа несколько раз — пир мёртв, SA удаляются, туннель переподнимается. MOBIKE (RFC 4555): клиент, у которого сменился адрес (телефон перешёл с Wi-Fi на сотовую сеть), шлёт UPDATE_SA_ADDRESSES, и все SA переезжают на новый адрес без нового рукопожатия. Это то, что делает IKEv2 удобным на мобильных.

NAT-T: IPsec через NAT

NAT из шестой части и ESP несовместимы с двух сторон: NAT переписывает адреса, а у ESP нет портов, по которым он мог бы вести таблицу трансляций; два клиента за одним NAT с ESP к одному серверу вообще не различимы. Поэтому в IKE_SA_INIT есть NAT detection: каждая сторона присылает хеш от своего адреса и порта, как она их видит. Получатель считает тот же хеш от адреса и порта, с которых пакет пришёл. Не совпало — по дороге NAT.

Тогда обе стороны переходят на UDP 4500: IKE продолжает там же с четырьмя нулевыми байтами впереди (non-ESP marker), а ESP-пакеты заворачиваются в UDP на тот же порт — UDP-encapsulated ESP. У NAT появляются порты, у клиентов за одним NAT — разные внешние порты, всё работает. Цена — 8 байт UDP на пакет и необходимость держать запись NAT живой: клиент шлёт keepalive, однобайтовый UDP-пакет 0xFF, каждые 20 секунд, ровно по причинам из девятой части.

$ sudo tcpdump -i eth0 -n 'udp port 500 or udp port 4500 or esp'
IP 198.51.100.2.500 > 203.0.113.5.500: isakmp: parent_sa ikev2_init[I]
IP 203.0.113.5.500 > 198.51.100.2.500: isakmp: parent_sa ikev2_init[R]
IP 198.51.100.2.4500 > 203.0.113.5.4500: NONESP-encap: isakmp: child_sa  ikev2_auth[I]
IP 203.0.113.5.4500 > 198.51.100.2.4500: NONESP-encap: isakmp: child_sa  ikev2_auth[R]
IP 198.51.100.2.4500 > 203.0.113.5.4500: UDP-encap: ESP(spi=0xc1a2b3d4,seq=0x1), length 132
IP 203.0.113.5.4500 > 198.51.100.2.4500: UDP-encap: ESP(spi=0x9e8f7a6b,seq=0x1), length 132
IP 198.51.100.2.4500 > 203.0.113.5.4500: isakmp-nat-keep-alive

tcpdump называет IKE старым именем isakmp. Видно всё, о чём была статья: INIT на 500, обнаружен NAT, AUTH уже на 4500 с маркером, ESP в UDP с SPI и номерами, keepalive. Что внутри ESP, не видно никому: ни адресов, ни портов, ни протокола — только размер и частота пакетов.

Файрволу для IPsec нужно: UDP 500, UDP 4500 и, если NAT нет, протокол ESP (50). AH (51) — если кто-то всё ещё его использует.


Политики или маршруты

Есть два способа решить, какой трафик идёт в туннель, и путаница между ними — вторая по частоте причина нерабочих туннелей после селекторов.

Policy-based — классика: SPD с селекторами перехватывает трафик, подходящий под политику, и отправляет в SA. Интерфейса у туннеля нет, в ip route он не виден, а трафик в него попадает, если совпал с селектором. Просто для «сеть A — сеть B», неудобно, когда нужны динамическая маршрутизация, несколько сетей или файрвол «на интерфейсе туннеля».

Route-based — туннель представлен интерфейсом (в Linux — XFRM interface или VTI), селекторы SA — «всё» (0.0.0.0/0), а что в туннель отправить, решает таблица маршрутов. Через такой интерфейс можно гонять протоколы динамической маршрутизации (OSPF внутри сети, BGP между сетями — роутеры по ним рассказывают друг другу о своих маршрутах, как мы упоминали в шестой части), ставить правила файрвола, видеть счётчики. Современные конфигурации чаще такие:

$ sudo ip link add ipsec0 type xfrm dev eth0 if_id 42
$ sudo ip link set ipsec0 up
$ sudo ip route add 10.0.0.0/24 dev ipsec0

и в SA/политиках указывается тот же if_id 42, чтобы стек связал интерфейс с туннелем.


Конфигурация и диагностика в strongSwan

Самая распространённая реализация IKE на Linux — strongSwan. Туннель шлюз-шлюз по сертификатам в swanctl.conf:

connections {
    office-b {
        remote_addrs = 203.0.113.5
        local  { auth = pubkey; certs = gw-a.pem; id = gw-a.example.com }
        remote { auth = pubkey; id = gw-b.example.com }
        children {
            lan {
                local_ts  = 192.168.1.0/24
                remote_ts = 10.0.0.0/24
                esp_proposals = aes256gcm16-x25519
                dpd_action = restart
                start_action = start
            }
        }
        proposals = aes256gcm16-prfsha256-x25519
        version = 2
        dpd_delay = 30s
    }
}

Каждая строка — что-то из статьи: proposals — набор для IKE_SA_INIT, esp_proposals — для Child SA, local_ts/remote_ts — селекторы, auth = pubkey — сертификаты, dpd_delay — интервал INFORMATIONAL.

Состояние:

$ sudo swanctl --list-sas
office-b: #1, ESTABLISHED, IKEv2, 1a2b3c4d5e6f7a8b_i* 8b7a6f5e4d3c2b1a_r
  local  'gw-a.example.com' @ 198.51.100.2[4500]
  remote 'gw-b.example.com' @ 203.0.113.5[4500]
  AES_GCM_16-256/PRF_HMAC_SHA2_256/CURVE_25519
  established 1234s ago, rekeying in 12345s
  lan: #1, reqid 1, INSTALLED, TUNNEL-in-UDP, ESP:AES_GCM_16-256
    installed 1234s ago, rekeying in 2345s, expires in 3456s
    in  c1a2b3d4,   12345 bytes,   123 packets,     2s ago
    out 9e8f7a6b,   23456 bytes,   234 packets,     2s ago
    local  192.168.1.0/24
    remote 10.0.0.0/24

ESTABLISHED — IKE SA есть, INSTALLED — Child SA в ядре, TUNNEL-in-UDP — сработал NAT-T, SPI на оба направления и счётчики. Если in растёт, а out нет — пакеты от нас в туннель не попадают: смотреть политики и маршруты. Если оба нули — трафик не подходит под селекторы. Если SA в состоянии CONNECTING — смотреть лог journalctl -u strongswan: там будет, на каком сообщении остановились (нет ответа на INIT — файрвол или адрес; AUTH failed — ключи, сертификаты, идентификаторы; NO_PROPOSAL_CHOSEN — не сошлись алгоритмы; TS_UNACCEPTABLE — селекторы).


Что запомнить

  • IPsec защищает IP-пакеты: ESP (50) шифрует и подписывает, AH (51) только подписывает и почти не используется. Транспортный режим — между хостами, исходный заголовок остаётся; туннельный — весь пакет внутри нового, для шлюзов и удалённого доступа.
  • SA — односторонняя: SPI, алгоритмы, ключи, срок; пара на туннель; SPD говорит, какой трафик куда. В Linux это ip xfrm state и ip xfrm policy.
  • IKEv2: IKE_SA_INIT (алгоритмы, DH, nonces, открыто), IKE_AUTH (подпись первого сообщения через PSK, сертификат или EAP; селекторы; первая Child SA; адрес через CP), CREATE_CHILD_SA (ещё SA и rekey), INFORMATIONAL (DPD, удаление, MOBIKE).
  • NAT ломает ESP; NAT-T обнаруживает NAT в INIT и уводит всё в UDP 4500 с keepalive раз в 20 секунд. Открывать UDP 500, 4500 и ESP.
  • Туннель поднялся, а трафик не идёт — селекторы или политики/маршруты. MTU туннеля меньше на 50–70 байт, MSS clamping обязателен.

Дальше — Часть 20: VPN и прокси: что такое VPN в терминах уровней и интерфейсов, как на примере IKEv2 remote access клиент получает адрес, маршруты и DNS, что такое split tunneling и утечки DNS, как устроены HTTP CONNECT и SOCKS, и почему то, что называют VPN в расширениях браузера, обычно прокси.


Серия «Сети для самых маленьких»

  1. Модели OSI и TCP/IP — зачем сетевой стек разбит на уровни и как данные обрастают заголовками по пути пакета.
  2. Ethernet — кадр по байтам, MAC-адреса и как коммутатор решает, в какой порт отправить кадр.
  3. Wi-Fi — чем радио отличается от кабеля, как клиент подключается к точке доступа и как защищается эфир.
  4. PPPoE — как провайдер заворачивает сессию абонента в Ethernet и откуда берётся MTU 1492.
  5. IPv4: адреса, маски и подсети — как читать адрес и маску, делить сеть на подсети и решать, нужен ли шлюз.
  6. IPv4: заголовок, маршрутизация и NAT — как роутер выбирает маршрут для пакета и как вся квартира выходит в интернет с одного адреса.
  7. ARP — как по IP-адресу соседа узнать его MAC-адрес и почему соседа так легко подменить.
  8. ICMP — служебные сообщения IP, как на самом деле работают ping и traceroute и что ломается, когда их режут.
  9. UDP — восемь байт заголовка, порты и почему отправка без соединения иногда лучше.
  10. TCP — как из ненадёжного IP получается надёжный поток байтов и почему потеря пакета режет скорость.
  11. DHCPv4 — как машина без адреса получает адрес, маску, шлюз и DNS четырьмя сообщениями.
  12. DNS — как имя превращается в адрес: дерево зон, рекурсивные серверы, записи и кеширование.
  13. IPv6: адреса и заголовок — как записываются 128-битные адреса, какие они бывают и чем заголовок IPv6 отличается от IPv4.
  14. ICMPv6 и Neighbor Discovery — как в IPv6 без ARP и широковещания находят соседей и роутер.
  15. SLAAC — как хост собирает себе адрес IPv6 из объявления роутера без всякого сервера.
  16. DHCPv6 — зачем DHCP, если есть SLAAC, и как провайдер выдаёт домашнему роутеру целый блок сетей.
  17. VLAN — как один коммутатор и один кабель несут несколько независимых сетей.
  18. VXLAN — как растянуть сеть Ethernet через роутеры, завернув кадры в UDP.
  19. IPsec и IKEv2 (эта статья) — как шифруют пакеты на сетевом уровне и договариваются о ключах.
  20. VPN и прокси — куда уходит каждый пакет при включённом VPN и чем прокси отличается от VPN.
  21. OSPF — как роутеры одной сети сами строят общую карту и считают по ней кратчайшие пути.
  22. BGP — как десятки тысяч независимых сетей интернета договариваются о маршрутах.
  23. TLS и сертификаты — как защищают одно TCP-соединение и откуда браузер знает, что сервер настоящий.

Оставить комментарий могут только зарегистрированные пользователи.

Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.