Протокол транспортної безпеки TLS 1.3 надійно захищає зміст інтернет-трафіку від перехоплення провайдерами та транзитними вузлами. Проте на рівні метаданих залишається суттєвий недолік: кінцевий сервер завжди безпосередньо бачить вихідну IP-адресу клієнта.
У звичайних умовах це розглядається як фундаментальна властивість адресації. Однак під час виконання конфіденційних дій — передавання запитів до систем штучного інтелекту (LLM), надсилання звітів про збої в ОС, біометричної автентифікації чи географічних розрахунків — IP-адреса виступає стабільним ідентифікатором. Зіставляючи часові позначки та мережеві адреси, сервери цільових сервісів формують детальні профілі користувачів навіть за відсутності авторизації в системі.
Традиційні проксі-сервери лише зміщують вектор ризику: оператор проксі отримує повний доступ як до реальної IP-адреси пристрою, так і до відкритих назв серверів призначення. Для розв'язання цієї проблеми без потреби у централізованій довірі інженерна група IETF ухвалила специфікацію RFC 9458 (Oblivious HTTP, OHTTP), що спирається на стандарти RFC 9180 (Hybrid Public Key Encryption, HPKE) та RFC 9292 (Binary HTTP).
+--------------------------------------------------------------------------+
| АРХІТЕКТУРА RFC 9458 OBLIVIOUS HTTP |
+--------------------------------------------------------------------------+
| |
| +------------+ 1. Зашифрований запит (HPKE) +------------+ |
| | | --------------------------------------> | Шлюз | |
| | Клієнт | <-------------------------------------- | ретрансля- | |
| | (Браузер / | 4. Зашифрована відповідь (HPKE) | ції (Relay)| |
| | AI Agent) | +------------+ |
| +------------+ | |
| | 2. Переси-|3. Надіс-
| | (IP-адреса клієнта доступна ЛИШЕ Relay) лання |лання |
| | (Дані зашифровані публічним ключем Target) шифротек- |відповіді
| | сту |в шифрі |
| | v |
| | +------------+ |
| +----------------------------------------------> | Цільовий | |
| (Наскрізна криптографічна межа) | сервер | |
| Сервер Target розшифровує через HPKE | (Target) | |
| Target бачить ЛИШЕ IP-АДРЕСУ ШЛЮЗУ RELAY +------------+ |
| |
+--------------------------------------------------------------------------+
Криптографічні засади: схема HPKE та формат Binary HTTP
Специфікація RFC 9458 базується на обов'язковому розмежуванні обов'язків між двома незалежними вузлами: шлюзом ретрансляції (Relay) та сервером призначення (Target). Шлюз Relay пересилає закриті пакети, не маючи можливості їх дешифрувати; сервер Target обробляє дані, але бачить виключно IP-адресу шлюзу ретрансляції.
Цей захист забезпечується двома базовими технологіями:
1. Бінарне кадрування Binary HTTP (RFC 9292)
Звичайні HTTP-запити складаються з текстових заголовків і довільного тіла пакета. В архітектурі OHTTP запит цілком перетворюється на стандартизований масив бінарних байтів за правилами RFC 9292 (BHTTP):
+--------------------+--------------------------------+--------------------+
| Керуючі поля кадру | Індексовані заголовки | Корисне тіло |
| (GET /api/v1/query)| (Host: target.example.com ...) | (Бінарні дані) |
+--------------------+--------------------------------+--------------------+
Такий формат виключає розбіжності парсингу на транспортному рівні перед виконанням криптографічних дій.
2. Гібридне шифрування з відкритим ключем (HPKE, RFC 9180)
Для захисту бінарного запиту від аналізу на шлюзі Relay клієнт шифрує його за допомогою конфігурації відкритого ключа Target. Сервер Target надає публічну конфігурацію OHTTP:
key_id: ідентифікатор версії ключа розміром 1 байт для ротації;kem_id: механізм інкапсуляції ключа (0x0020для DHKEM на Curve25519);kdf_id: функція деривації ключа (0x0001для HKDF-SHA256);aead_id: алгоритм автентифікованого шифрування (0x0001для AES-128-GCM або0x0003для ChaCha20-Poly1305);public_key: публічні байти цільового ключа Target.
У базовому режимі HPKE клієнт генерує одноразову пару ключів $(sk_E, pk_E)$ та обчислює спільний секрет із ключем $pk_T$:
$$ ext{SharedSecret} = ext{DH}(sk_E, pk_T)$$
Застосовуючи алгоритм HKDF, клієнт створює сесійний ключ шифрування $K_{ ext{req}}$ та вектор ініціалізації $N_{ ext{req}}$:
$$(K_{ ext{req}}, N_{ ext{req}}) = ext{KeyDerivation}( ext{SharedSecret}, ext{info})$$
Після цього бінарний запит BHTTP пакується у шифротекст $C_{ ext{req}}$:
$$C_{ ext{req}} = ext{Seal}(K_{ ext{req}}, N_{ ext{req}}, ext{aad}, ext{BinaryHTTPRequest})$$
Отримане повідомлення з MIME-типом message/ohttp-req має структуру:
[KeyID (1 байт)] || [KEM (2 байти)] || [KDF (2 байти)] || [AEAD (2 байти)] || [enc (32 байти)] || [Шифротекст]
Оскільки відповідний закритий ключ зберігається виключно на сервері Target, шлюз Relay технічно не може розкрити чи змінити корисні дані.
+--------------------------------------------------------------------------+
| РОЗПОДІЛ ДОСТУПУ ДО ДАНИХ У МЕРЕЖІ |
+--------------------------------------------------------------------------+
| Сторона | Бачить реальну IP? | Читає тіло запиту? | Читає відповідь?|
+--------------+--------------------+--------------------+-----------------+
| Провайдер | Так | НІ (Захист TLS) | НІ |
| Шлюз Relay | Так (або IP VPN) | НІ (Шифр HPKE) | НІ |
| Сервер Target| НІ (Бачить Relay) | ТАК (Розшифровано) | ТАК |
+--------------------------------------------------------------------------+
Послідовність виконання сесії Oblivious HTTP
Процедура обміну даними за протоколом OHTTP складається з п'яти дій:
- Отримання конфігурації ключів: Клієнт завантажує актуальну публічну конфігурацію Target через записи DNS HTTPS або безпечні каталоги ключів.
- Формування шифрованого пакета: Клієнт кодує запит у формат BHTTP, формує контекст HPKE, запечатує дані та генерує бінарний блок
message/ohttp-req. - Ретрансляція через Relay: Клієнт надсилає пакет на шлюз Relay методом HTTPS
POST /relay. Шлюз завершує сесію TLS, вилучає заголовки з адресою клієнта і передає дані до Target у новому з'єднанні. - Розшифрування та обробка на Target: Сервер призначення звіряє
key_id, розпаковуєenc, відновлює спільний секрет, дешифрує пакет і вилучає Binary HTTP. Виконується необхідна бізнес-логіка (наприклад, обробка промпту моделі AI), а результат пакується у формат BHTTP. - Інкапсуляція відповіді: Target створює ключ $K_{ ext{res}}$ із контексту HPKE, запечатує відповідь у контейнер
message/ohttp-resі надсилає його назад на Relay. Шлюз пересилає контейнер клієнту для остаточного розшифрування.
Взаємодія з протоколом RiceGuard та мережевим рівнем L3
Незважаючи на те, що Oblivious HTTP працює на прикладному рівні (L7), його поєднання з тунелями третього рівня (L3) протоколу RiceGuard сервісу VPNRice формує комплексний багаторівневий захист:
- Усунення загрози профілювання на Relay: Під час маршрутизації через RiceGuard шлюз Relay бачить спільну вихідну адресу пулу VPN, а не домашню точку доступу. Навіть у разі компрометації шлюзу Relay встановити особу кінцевого користувача неможливо.
- Повна ізоляція запитів DNS: Звернення до DNS під час пошуку адрес Relay та Target здійснюються суто всередині захищеного простору мережі RiceGuard.
- Захист локальних агентів штучного інтелекту: Автономні агенти AI, що звертаються до хмарних інструментів, можуть передавати запити через OHTTP поверх тунелів RiceGuard, завдяки чому постачальники моделей не зберігають IP-ідентифікаторів користувачів.
Програмна реалізація клієнта OHTTP мовою Go
Нижче наведено робочий приклад клієнтського модуля мовою Go, що здійснює інкапсуляцію запиту Binary HTTP за специфікацією RFC 9458:
package main
import (
"bytes"
"crypto/rand"
"fmt"
"io"
"net/http"
"github.com/cloudflare/circl/hpke"
)
type OHTTPEncapsulator struct {
suite hpke.Suite
targetPK hpke.PublicKey
keyID uint8
}
func NewOHTTPEncapsulator(keyID uint8, kemID hpke.KEM, kdfID hpke.KDF, aeadID hpke.AEAD, rawPubKey []byte) (*OHTTPEncapsulator, error) {
suite := hpke.NewSuite(kemID, kdfID, aeadID)
pk, err := suite.KEM().Scheme().UnmarshalBinaryPublicKey(rawPubKey)
if err != nil {
return nil, fmt.Errorf("помилка читання відкритого ключа: %w", err)
}
return &OHTTPEncapsulator{
suite: suite,
targetPK: pk,
keyID: keyID,
}, nil
}
// EncapsulateRequest пакує бінарне повідомлення у контейнер message/ohttp-req
func (oe *OHTTPEncapsulator) EncapsulateRequest(bhttpReq []byte) ([]byte, hpke.Context, error) {
sender, err := oe.suite.NewSender(oe.targetPK, []byte("message/bhttp request"))
if err != nil {
return nil, nil, fmt.Errorf("не вдалося ініціалізувати HPKE sender: %w", err)
}
enc, ctx, err := sender.Setup(rand.Reader)
if err != nil {
return nil, nil, fmt.Errorf("помилка налаштування контексту HPKE: %w", err)
}
ciphertext, err := ctx.Seal(nil, bhttpReq)
if err != nil {
return nil, nil, fmt.Errorf("помилка шифрування даних: %w", err)
}
var buf bytes.Buffer
buf.WriteByte(oe.keyID)
buf.Write([]byte{0x00, 0x20}) // DHKEM(X25519, HKDF-SHA256)
buf.Write([]byte{0x00, 0x01}) // HKDF-SHA256
buf.Write([]byte{0x00, 0x01}) // AES-128-GCM
buf.Write(enc)
buf.Write(ciphertext)
return buf.Bytes(), ctx, nil
}
func SendToRelay(relayURL string, targetURL string, ohttpPayload []byte) ([]byte, error) {
req, err := http.NewRequest("POST", relayURL, bytes.NewReader(ohttpPayload))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "message/ohttp-req")
req.Header.Set("Target", targetURL)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("помилка надсилання на релей: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("шлюз відхилив запит: HTTP %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
Інженерні компроміси та практичні висновки
Практичне застосування стандарту RFC 9458 потребує зваженого технічного підходу:
- Додаткова затримка мережі: Проходження через два фізичні сервери (Клієнт $ o$ Relay $ o$ Target) збільшує час кругового обігу пакетів (RTT) на 20–45 мс. Протокол якнайкраще підходить для API-викликів, телеметрії та AI-запитів, але не для завантаження важких веб-сторінок.
- Особливості кешування: Мережі CDN кешують контент на основі аналізу URL-шляхів. Через непрозорість тіла OHTTP проміжне кешування вимагає спеціальних тегів.
- Організаційна незалежність: Модель безпеки втрачає чинність, якщо Relay і Target контролюються однією компанією. Обов'язковою вимогою є експлуатація цих компонентів незалежними операторами.
Специфікація RFC 9458 Oblivious HTTP підтверджує, що сучасний інтернет здатен забезпечувати надійну конфіденційність без потреби жертвувати сумісністю із веб-стандартами.



