Проксі для облікових даних — технічні аспекти
Як працює проксі.
Від чого він захищає. Від чого ні.
Ця сторінка призначена для оглядачів безпеки, тестувальників на проникнення та інженерів, які оцінюють модель загроз проксі. Вона описує, що робить проксі на рівні протоколу, де облікові дані зберігаються в пам'яті та які поверхні атаки залишаються.
Архітектура
Проксі є проксі-сервером HTTPS MITM на основі CONNECT. ШІ-агент встановлює HTTPS_PROXY для вказівки на нього. Коли агент робить HTTPS-запит, проксі перехоплює TLS-з'єднання, перевіряє заголовки запиту на наявність посилань на облікові дані, розпізнає їх у сховищі Clavitor та пересилає запит із вставленими обліковими даними до вихідного API.
За замовчуванням проксі прослуховує 127.0.0.1:1983 — шаблон sidecar, де проксі та агент спільно використовують хост. Для спільних розгортань (один проксі обслуговує кілька агентів у приватній мережі, контейнерний sidecar для кількох робочих навантажень, виділений хост проксі) інтерфейс прослуховування можна налаштувати за допомогою CLAVITOR_PROXY_LISTEN.
Проксі є окремим бінарним файлом Go. Без CGO. Уся криптографія протоколу Clavitor проходить через канонічну реалізацію Rust, скомпільовану в WebAssembly та завантажену через wazero під час запуску.
Обробка TLS
Проксі генерує самопідписаний кореневий ЦС ECDSA P-256 під час першого запуску, зберігаючи його в каталозі бінарного файлу з правами доступу 0600. Для кожного вихідного хоста сертифікат листа створюється за запитом, підписується цим ЦС і кешується в пам'яті з обмеженим витісненням (1000 хостів). Сертифікати листів дійсні протягом 24 годин і прозоро перегенеруються на 23-й годині, щоб запобігти закінченню терміну дії під час сесії.
Агент повинен довіряти сертифікату ЦС проксі. Експортуйте його за допомогою clavitor-proxy ca.
Вихідні з'єднання використовують мінімум TLS 1.3 з узгодженням ALPN для HTTP/2 та HTTP/1.1. Для перевірки вихідних з'єднань використовується системний пул сертифікатів. Без закріплення сертифікатів — проксі довіряє всьому, чому довіряє ОС.
Облікові дані ніколи не кешуються, ніколи не записуються на диск і ніколи не зберігаються довше одного HTTP-запиту.
| Фаза | Де зберігаються облікові дані | Тривалість |
|---|---|---|
| У стані спокою у сховищі | Шифротекст AES-GCM у базі даних сховища | До видалення |
| Під час передачі до проксі | JSON-відповідь від API сховища, зашифрована TLS | Один повний цикл HTTP-запиту |
| Розшифровано в проксі | Пам'ять процесу (рядок Go в купі) | Один HTTP-запит |
| Вставлено в вихідний запит | Байти, зашифровані TLS, у мережі до вихідного сервера | Один HTTP-запит |
Проксі зберігає ключ розшифрування облікових даних агента (16 байтів) у пам'яті протягом усього часу роботи. Він завантажується з зашифрованої конфігурації sidecar (формат CLV1) під час запуску та очищається під час коректного завершення роботи. Ключ ніколи не залишає процес.
Конфігурація sidecar шифрується за допомогою AES-128-GCM та HMAC-SHA256 з використанням детермінованих ключів, отриманих зі статичного насіння. Це обфускація, а не конфіденційність — межа безпеки — це дозволи файлів (0600) та володіння файлом. Формат CLV1 є спільним для проксі, CLI та розширення браузера.
Режими розпізнавання
Режим 1 — явний плейсхолдер
Агент включає посилання clavitor://Entry/field у заголовку запиту. Проксі шукає запис у сховищі за назвою, отримує його, розшифровує назване поле та замінює плейсхолдер фактичним значенням.
Якщо пошук повертає нуль або більше одного результату, проксі повертає 502 зі стабільним кодом помилки. Плейсхолдер ніколи не видаляється та не пересилається як є.
Режим 2 — відповідність URL
Коли плейсхолдер відсутній, проксі запитує у сховища записи, поле URL яких відповідає вихідному хосту. Якщо існує рівно один збіг із розпізнаваною формою поля, проксі автоматично вставляє облікові дані.
Нуль збігів → пропуск (без очікування облікових даних). Кілька збігів → 502 з рекомендаціями щодо усунення неоднозначності. Невідома форма поля → 502.
Дерево рішень є детермінованим: плейсхолдер присутній → розпізнати або помилка. Плейсхолдер відсутній → відповідність URL або пропуск. Немає шляху мовчазного резервного варіанту, коли невдале розпізнавання призводить до надсилання запиту до вихідного сервера без облікових даних.
За замовчуванням сховище бачить власний ідентифікатор агента проксі з кожним запитом. Обмеження швидкості, перевірки області дії та записи аудиту приписуються проксі.
Коли кілька агентів спільно використовують один екземпляр проксі, плейсхолдер може включати ідентифікатор агента: clavitor://agentid@Entry/field. Проксі надсилає цей ідентифікатор агента до сховища, яке застосовує області дії та обмеження швидкості цього агента та реєструє доступ до нього. Ідентифікатор агента — це 32-символьне шістнадцяткове значення, показане на сторінці деталей агента в інтерфейсі користувача сховища.
# Without agent ID — attributed to the proxy Authorization: Bearer clavitor://OpenAI/key # With agent ID — attributed to agent 0102030405060708090a0b0c0d0e0f10 Authorization: Bearer clavitor://0102030405060708090a0b0c0d0e0f10@OpenAI/key
| Розгортання | Модель ідентифікації | Ізоляція |
|---|---|---|
| Один проксі на агента | ID проксі = ID агента (за замовчуванням) | Повна — окремий бінарний файл, конфігурація, область дії, обмеження швидкості |
| Спільний проксі, без ID агента в URL | Усі агенти спільно використовують ID проксі | Спільна область дії та обмеження швидкості |
Спільний проксі + agentid@ в URL | Ідентифікатор на агента | Область дії, обмеження швидкості та аудит на агента |
Ідентифікатор агента в URL не є механізмом автентифікації — токен CVT проксі автентифікує з'єднання. Ідентифікатор агента визначає приписування: чиї області дії застосовуються, чиї обмеження швидкості враховуються, чий журнал аудиту записує доступ. Сховище відхиляє невідомі ідентифікатори агентів з гучним збоєм.
Мережева безпека
Захист від SSRF
За замовчуванням проксі блокує вихідні з'єднання до приватних мереж (RFC 1918), метаданих екземплярів хмари (169.254.169.254), петльових, канальних та діапазонів NAT операторського класу. DNS розпізнається першим; усі повернуті IP-адреси перевіряються перед встановленням TCP-з'єднання, закриваючи вікно TOCTOU для прив'язки DNS.
Перевизначте за допомогою CLAVITOR_PROXY_ALLOW_PRIVATE=true для агентів, які законно досягають приватних API.
Закріплення цілі
Цільовий хост CONNECT захоплюється під час встановлення тунелю та використовується протягом усього терміну дії тунелю. Наступні запити в межах тунелю не можуть перенаправлятися на інший хост шляхом маніпулювання заголовком Host. Невідповідність призводить до 502.
Це запобігає встановленню агентом тунелю до api.openai.com з подальшим надсиланням запитів до internal-service.corp.
Обробка заголовків
Заголовки "hop-by-hop" видаляються з запитів та відповідей відповідно до RFC 7230 §6.1: Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, Proxy-Connection, TE, Trailers, Transfer-Encoding, Upgrade.
Set-Cookie видаляється з відповідей вихідних серверів, щоб запобігти розміщенню файлів cookie у HTTP-клієнті агента.
Тіла запитів і відповідей передаються без буферизації. Тіла запитів обмежені 64 МБ за замовчуванням (CLAVITOR_PROXY_MAX_BODY_MB). Тіла відповідей передаються без жорсткого обмеження; попередження в журналі видається, коли Content-Length перевищує 100 МБ.
У режимі відповідності URL проксі зіставляє мітки полів сховища з HTTP-заголовками:
| Мітка поля | Вставлений заголовок |
|---|---|
key, apikey, api_key, token, secret, bearer, access_token | Authorization: Bearer <value> |
x-api-key, api-key | X-API-Key: <value> |
username + password (у парі) | Authorization: Basic base64(user:pass) |
| Будь-що інше | Відхилено — ERR-PROXY-052 |
У режимі плейсхолдера агент контролює, яке поле розпізнається і куди воно йде. Наведене вище зіставлення застосовується лише до режиму відповідності URL.
Кожен збій генерує стабільний код ERR-PROXY-NNN. Ці коди є частиною публічного інтерфейсу проксі — агенти та оператори можуть зіставляти їх для сповіщень та налагодження.
| Діапазон | Категорія |
|---|---|
001–019 | Налаштування (конфігурація, ініціалізація, генерація ЦС, WASM) |
020–029 | Життєвий цикл демона |
030–049 | Розпізнавання плейсхолдерів (URI clavitor://) |
050–069 | Вставка за відповідністю URL |
070–089 | Вихідний / TLS |
Поля ідентифікації недоступні
Записи сховища підтримують три рівні шифрування. Поля, зашифровані сховищем, є метаданими у відкритому тексті. Поля, зашифровані обліковими даними, розшифровуються ключем агента. Поля, зашифровані ідентифікаційними даними, шифруються ключем, якого сервер і проксі ніколи не бачили. Лише власник сховища за допомогою свого апаратного ключа безпеки може їх розшифрувати.
Якщо плейсхолдер посилається на поле, зашифроване ідентифікаційними даними, проксі повертає ERR-PROXY-035. Без резервного варіанту, без часткового результату. Поле архітектурно недоступне з проксі.
Те, від чого проксі не захищає
Модель загроз проксі — це компрометація навички або впровадження підказки, що змушує автентифікованого агента збирати облікові дані. Первинними засобами захисту є обмеження швидкості для кожного агента у сховищі, унікальні квоти на записи та блокування після двох порушень. Проксі додає точку примусового виконання на рівні мережі, де облікові дані розпізнаються для кожного запиту і ніколи не зберігаються агентом.
Проксі працює на тій самій машині, що й агент. Зловмисник з root-доступом може читати пам'ять процесу, підключати налагоджувач або перехоплювати трафік зворотного виклику. Проксі є рівнем вставки облікових даних, а не межею апаратного забезпечення безпеки.
Якщо вихідний API повертає облікові дані у своїй відповіді (наприклад, кінцева точка "хто я"), агент їх бачить. Проксі вставляє облікові дані в запити, а не у відповіді. Він не фільтрує те, що повертається.
Журналювання
Проксі реєструє один рядок на прийнятий CONNECT і виводить рядки помилок для збоїв. Він ніколи не реєструє:
- Розшифровані значення облікових даних
- Повні URL-адреси запитів (рядки запитів можуть містити секрети — реєструються лише схема + хост + шлях)
- Тіла запитів або відповідей
- Ключ розшифрування облікових даних або вміст конфігурації sidecar
Коли проксі виявляє, що відповідь 400 від вихідного сервера містить ключові слова, пов'язані з автентифікацією (unauthorized, invalid token тощо), він реєструє діагностичну підказку, яка припускає, що вставлені облікові дані можуть бути застарілими. Відповідь пересилається без змін.
Криптографія
Уся криптографія протоколу Clavitor — розшифрування полів AES-GCM, виведення ключів HKDF, кодування base62, створення токенів CVT, пакування/розпакування конфігурації CLV1 — виконується в одному модулі WebAssembly (clavis_crypto.wasm), завантаженому через wazero, чистий WASM-рантайм Go. Без CGO. Без реалізації примітивів Clavitor на Go.
Модуль WASM скомпільований з того самого крейту Rust (clavis-crypto), який використовується браузером, CLI та розширеннями браузера. Одне джерело правди, один бінарний файл, одна поверхня аудиту.
Проксі використовує crypto/tls Go для TLS-трафіку та crypto/ecdsa для генерації сертифікатів MITM. Це транспортні аспекти, а не операції протоколу Clavitor.
Секрети (ключ розшифрування облікових даних, ID агента, ID пристрою, URL сховища) зберігаються в зашифрованій конфігурації sidecar CLV1, записаній один раз під час clavitor-proxy init. Операційні важелі знаходяться в змінних середовища:
| Змінна | За замовчуванням | Призначення |
|---|---|---|
CLAVITOR_PROXY_LISTEN | 127.0.0.1 | Інтерфейс прослуховування. Встановіть 0.0.0.0 для спільних розгортань або для конкретної IP-адреси інтерфейсу. |
CLAVITOR_PROXY_PORT | 1983 | Порт прослуховування |
CLAVITOR_PROXY_ALLOW_PRIVATE | false | Дозволити з'єднання до приватних мереж / RFC-1918 |
CLAVITOR_PROXY_MAX_BODY_MB | 64 | Обмеження розміру тіла запиту |
CLAVITOR_PROXY_WRITE_TIMEOUT | 300 | Час очікування запису відповіді в секундах |
CLAVITOR_CONFIG | (каталог exe) | Перевизначити шлях до конфігурації sidecar |
Операційні важелі не є секретами. Вони не належать до зашифрованої конфігурації. Вони належать туди, де інструменти розгортання вже керують ними — у середовище.
Перегляньте це самостійно.
Криптографія — це єдиний артефакт WASM, який можна перевірити. Модель загроз задокументована. Якщо ви знайдете щось, що ми пропустили, ми хочемо про це почути.