VLESS Encryption
VLESS Encryption - Документация
Заголовок раздела «VLESS Encryption - Документация»Содержание
Заголовок раздела «Содержание»- Введение
- Криптографическая архитектура
- Режимы работы
- Формат конфигурации
- Генерация ключей
- Примеры конфигураций
- Сравнение с другими протоколами
- Производительность
- Безопасность
- Технические детали
- Best Practices
- Troubleshooting
Введение
Заголовок раздела «Введение»Что такое VLESS Encryption?
Заголовок раздела «Что такое VLESS Encryption?»VLESS Encryption - это легковесное, квантово-устойчивое шифрование с Perfect Forward Secrecy (PFS) для протокола VLESS, добавленное в Xray-core в PR #5067.
Ключевые особенности:
- 🔐 Post-Quantum криптография: ML-KEM-768 + X25519
- 🚀 0-RTT: Первое соединение 1-RTT, последующие 0-RTT через ticket
- 🛡️ Perfect Forward Secrecy: Компрометация ключей не раскрывает прошлый трафик
- 🎭 Три режима внешнего вида: native / xorpub / random
- ⚡ Совместимость с XTLS: ReadV/Splice для максимальной производительности
- 🔒 Защита конфигурации клиента: Утечка конфига не раскрывает прошлый/будущий трафик
Для чего использовать?
Заголовок раздела «Для чего использовать?»⚠️ ВАЖНО: VLESS Encryption НЕ предназначен для прямого обхода GFW!
Правильные сценарии использования:
- 🌐 CDN: Защита UUID и SNI при проксировании через CDN
- 🔄 Транзит/Relay: Цепочки прокси без TLS (например, запрет HTTP/TLS на транзитных серверах)
- 🇮🇷 Non-TLS: Страны с ограничениями TLS (Иран)
- 🏢 Обход аудита провайдера: Шифрование трафика до собственного VPS через общедоступные линии
Для прямого обхода блокировок используйте:
Преимущества перед SS/VMess
Заголовок раздела «Преимущества перед SS/VMess»| Характеристика | VLESS Encryption | SS 2022/AEAD | VMess AEAD |
|---|---|---|---|
| Внешний вид трафика | Настраиваемый (native/xorpub/random) | Random | Random |
| Клиент config безопасность | ✅ | ❌ | ❌ |
| Perfect Forward Secrecy | ✅ | ❌ | ❌ |
| Квантовая устойчивость | ✅ | ❌ | ❌ |
| RTT overhead | 0-RTT (после 1-RTT) | 0-RTT | 0-RTT |
| Защита от replay | ✅ Идеальная | ⚠️ Ограниченная | ⚠️ Требует синхронизации времени |
| Определение пользователя | O(1) по ticket | O(n) перебор | O(n) перебор |
| Extra AEAD length | ❌ | ✅ +13 байт | ❌ |
| XTLS совместимость | ✅ | ❌ | ❌ |
| Производительность | 10% быстрее | Базовая | Базовая |
Криптографическая архитектура
Заголовок раздела «Криптографическая архитектура»Гибридное Post-Quantum шифрование
Заголовок раздела «Гибридное Post-Quantum шифрование»VLESS Encryption использует MLKEM768X25519 - гибридную схему обмена ключами:
┌─────────────────────────────────────────────────────────┐│ MLKEM768X25519 = ML-KEM-768 ⊕ X25519 ││ ││ • ML-KEM-768: Квантово-устойчивый KEM (NIST) ││ • X25519: Классический ECDH (быстрый, проверенный) ││ ││ Защита: Даже если один алгоритм скомпрометирован, ││ второй обеспечивает безопасность │└─────────────────────────────────────────────────────────┘Почему гибрид?
- ML-KEM-768 защищает от квантовых компьютеров
- X25519 обеспечивает проверенную безопасность сегодня
- Компрометация любого из них не раскрывает трафик
Perfect Forward Secrecy (PFS)
Заголовок раздела «Perfect Forward Secrecy (PFS)»Концепция:
Время: T0 ────────► T1 ────────► T2 ────────► T3 │ │ │ │Ключи: K0 ────X K1 ────X K2 ────X K3 │ │ │ │Связь: Нет прямой связи между ключами разных сессий
Компрометация K3 не позволяет расшифровать трафик T0, T1, T2Реализация в VLESS Encryption:
-
nfsKey (Non-Forward-Secret Key): Предварительно распределенный ключ
- Генерируется из X25519/ML-KEM-768 пары клиент-сервер
- Используется для аутентификации и начального обмена
-
pfsKey (Perfect-Forward-Secret Key): Эфемерный ключ
- Генерируется для каждой сессии через MLKEM768X25519
- Уничтожается после использования
- Независим от nfsKey
-
unitedKey: Объединенный ключ
unitedKey = Hash(pfsKey || nfsKey)- Используется для шифрования данных
- Даже если ML-KEM-768 скомпрометирован в будущем, требуется и nfsKey
Защита конфигурации клиента
Заголовок раздела «Защита конфигурации клиента»Проблема в SS/VMess:
Атакующий получает клиентский конфиг (PSK) ↓Может расшифровать: • Весь прошлый трафик (если был записан) • Весь будущий трафик • Может выполнить MITM атакуРешение в VLESS Encryption:
Атакующий получает клиентский конфиг (публичный ключ сервера) ↓НЕ может расшифровать: • Прошлый трафик (требуются эфемерные ключи, уже уничтожены) • Будущий трафик (требуется приватный ключ сервера)
Может выполнить MITM только если: • Получит приватный ключ сервера (хранится только на сервере)Уровни защиты:
| Компрометация | SS 2022/AEAD | VLESS Encryption |
|---|---|---|
| Клиентский конфиг | ❌ Весь трафик доступен | ✅ Трафик защищен |
| Серверный ключ | ❌ Весь трафик доступен | ⚠️ Только будущий MITM |
| Клиент + Сервер | ❌ Полная компрометация | ⚠️ Будущий MITM (прошлое защищено) |
1-RTT vs 0-RTT
Заголовок раздела «1-RTT vs 0-RTT»1-RTT (первое соединение):
Клиент Сервер │ │ ├─── Client Hello ──────────────►│ (nfsKey зашифрован, эфемерный публичный ключ) │ │ │◄─── Server Hello ──────────────┤ (эфемерный публичный ключ, ticket, padding) │ │ ├─── Application Data ──────────►│ (unitedKey = pfsKey ⊕ nfsKey) │◄─── Application Data ──────────┤ │ │Задержка: +1 RTT (обмен ключами)
0-RTT (последующие соединения):
Клиент Сервер │ │ ├─── Ticket Hello ──────────────►│ (nfsKey зашифрован, ticket, данные) │ │ ↓ Сервер извлекает pfsKey из ticket │◄─── Application Data ──────────┤ (unitedKey, данные сразу) │ │Задержка: 0 RTT (данные в первом пакете)
Ticket механизм:
- Сервер шифрует pfsKey в ticket
- Ticket действителен 10 минут (настраивается: 300-600s)
- Клиент автоматически переключается между 1-RTT и 0-RTT
- После истечения ticket - автоматический возврат к 1-RTT
Режимы работы
Заголовок раздела «Режимы работы»VLESS Encryption поддерживает три режима внешнего вида трафика:
1. Native Mode
Заголовок раздела «1. Native Mode»Внешний вид: TLSv1.3-подобный (23 3 3 l>>8 l заголовки)
Характеристики:
- ✅ Минимальные вычислительные затраты
- ✅ Совместимость с XTLS ReadV/Splice
- ⚠️ Публичные ключи X25519/ML-KEM-768 видны в трафике
- ⚠️ AEAD заголовки имеют TLS-подобную структуру
Когда использовать:
- Прямое TCP соединение
- Транзит без DPI
- Максимальная производительность
Пример заголовка:
23 03 03 XX XX [AEAD encrypted data]│ │ │ │ ││ │ │ └──┴─ Length (big-endian)│ └──┴─────── TLS 1.3 version└──────────── Application Data (23)2. XOR Public Keys Mode (xorpub)
Заголовок раздела «2. XOR Public Keys Mode (xorpub)»Внешний вид: TLS-подобный, но публичные ключи замаскированы
Характеристики:
- ✅ Скрывает характеристики X25519/ML-KEM-768
- ✅ Совместимость с XTLS ReadV/Splice
- ✅ Минимальный overhead (~0.01% на ключи)
- ⚠️ AEAD заголовки остаются TLS-подобными
Процесс XOR:
Original Public Key: [32 bytes X25519] [1184 bytes ML-KEM-768] ↓ XOR ↓ XORXOR Mask: [derived from nfsKey] ↓ ↓Transmitted: [32 bytes XORed] [1184 bytes XORed]
Результат: Статистические характеристики публичных ключей скрытыКогда использовать:
- DPI может анализировать структуру ключей
- Relay цепочки
- Баланс между безопасностью и производительностью
3. Random Mode (random)
Заголовок раздела «3. Random Mode (random)»Внешний вид: Полностью случайный поток байт
Характеристики:
- ✅ Полная маскировка трафика
- ✅ XOR публичных ключей + заголовков
- ⚠️ Дополнительные вычисления: AES-256-CTR XOR на каждом пакете
- ⚠️ Overhead: ~0.06% трафика (только заголовки)
- ⚠️ Нет XTLS ReadV/Splice (используется XorConn)
Процесс XOR заголовков:
TLS-like Header: 23 03 03 XX XX ↓ XOR каждый байтRandom Stream: A7 B2 F4 C9 8E (из AES-256-CTR) ↓Result: 8A B1 F7 YY YY (случайные байты)Когда использовать:
- Максимальная скрытность
- Активный DPI с обнаружением паттернов
- Non-TLS окружения (Иран)
- Overhead 0.06% приемлем
⚠️ Важно: В random режиме XTLS не может пробить соединение полностью (только первая часть), так как XorConn не поддерживает ReadV/Splice.
Сравнение режимов
Заголовок раздела «Сравнение режимов»| Параметр | Native | XorPub | Random |
|---|---|---|---|
| CPU overhead | Минимальный | +0.01% | +0.06% |
| Bandwidth overhead | 0% | 0% | 0.06% |
| XTLS ReadV/Splice | ✅ Полная | ✅ Полная | ⚠️ Частичная |
| Скрытие ключей | ❌ | ✅ | ✅ |
| Скрытие заголовков | ❌ | ❌ | ✅ |
| DPI устойчивость | Низкая | Средняя | Высокая |
| Скорость | 🔥 Максимальная | 🔥 Максимальная | ⚡ Высокая |
Формат конфигурации
Заголовок раздела «Формат конфигурации»Структура параметра decryption (сервер)
Заголовок раздела «Структура параметра decryption (сервер)»mlkem768x25519plus.{mode}.{ticket}.{padding}.{keys}...│ │ │ │ ││ │ │ │ └─ X25519 PrivateKey (32 bytes)│ │ │ │ ML-KEM-768 Seed (64 bytes)│ │ │ │ (можно несколько пар)│ │ │ ││ │ │ └─ Padding параметры (опционально)│ │ ││ │ └─ Время жизни ticket (секунды)│ │ • 600s = 600 секунд (10 минут)│ │ • 300-600s = случайно от 300 до 600│ │ • 0s = отключить 0-RTT│ ││ └─ Режим: native / xorpub / random│└─ Префикс протокола (для будущих расширений)Примеры:
// Базовый (native, 10 минут ticket, padding по умолчанию)"decryption": "mlkem768x25519plus.native.600s..gK3C8vW...x25519Key.xK9mP2n...mlkemSeed"
// Без 0-RTT (только 1-RTT)"decryption": "mlkem768x25519plus.native.0s..gK3C8vW...x25519Key.xK9mP2n...mlkemSeed"
// Случайное время ticket (5-10 минут)"decryption": "mlkem768x25519plus.random.300-600s..gK3C8vW...x25519Key.xK9mP2n...mlkemSeed"
// С custom padding"decryption": "mlkem768x25519plus.xorpub.600s.100-200-500.80-50-200.gK3C8vW...x25519Key.xK9mP2n...mlkemSeed"Структура параметра encryption (клиент)
Заголовок раздела «Структура параметра encryption (клиент)»mlkem768x25519plus.{mode}.{rtt}.{padding}.{keys}...│ │ │ │ ││ │ │ │ └─ X25519 Password (32 bytes)│ │ │ │ ML-KEM-768 Client (1184 bytes)│ │ │ │ (можно несколько для relay)│ │ │ ││ │ │ └─ Padding параметры (опционально)│ │ ││ │ └─ Режим RTT: 0rtt / 1rtt│ │ • 0rtt = использовать ticket если есть│ │ • 1rtt = всегда 1-RTT handshake│ ││ └─ Режим: native / xorpub / random│└─ Префикс протоколаПримеры:
// Базовый (0-RTT если возможно)"encryption": "mlkem768x25519plus.native.0rtt..Ft5xRjE...x25519Pass.bH4kL7q...mlkemClient"
// Только 1-RTT"encryption": "mlkem768x25519plus.native.1rtt..Ft5xRjE...x25519Pass.bH4kL7q...mlkemClient"
// Два relay (цепочка)"encryption": "mlkem768x25519plus.xorpub.0rtt..Pass1.Client1.Pass2.Client2"Padding параметры
Заголовок раздела «Padding параметры»Padding используется для маскировки длины handshake пакетов от анализа трафика.
Формат одного padding блока:
probability-minDelay-maxDelay│ │ ││ │ └─ Максимальная задержка (мс) ИЛИ макс. размер padding (байты)│ ││ └─ Минимальная задержка (мс) ИЛИ мин. размер padding (байты)│└─ Вероятность срабатывания (0-100%)Значение по умолчанию:
100-111-1111.75-0-111.50-0-3333│ │ ││ │ └─ 3-й этап: 50% вероятность, 0-3333 байт padding│ ││ └─ 2-й этап: 75% вероятность, задержка 0-111 мс│└─ 1-й этап: 100% вероятность, 111-1111 байт padding после handshakeРабота padding:
1. Client/Server Hello отправлен ↓2. С вероятностью 100% добавляется 111-1111 байт padding ↓3. С вероятностью 75% задержка 0-111 мс ↓4. С вероятностью 50% отправляется еще 0-3333 байт padding ↓5. Начинается передача данныхCustom padding примеры:
// Агрессивный padding (больше данных)"100-500-2000.90-100-500.70-0-5000"
// Минимальный padding (только обязательный)"100-35-100"
// Без padding (не рекомендуется)"0"
// Использовать значения по умолчанию".." или пропустить параметр⚠️ Важно:
- Первый padding должен иметь вероятность 100% и минимум 35 байт
- Padding применяется только к 1-RTT handshake
- Padding увеличивает размер первого пакета, но защищает от fingerprinting
Генерация ключей
Заголовок раздела «Генерация ключей»CLI команды Xray
Заголовок раздела «CLI команды Xray»1. X25519 ключи
Заголовок раздела «1. X25519 ключи»# Генерация случайной пары./xray x25519
# Вывод:# PrivateKey: gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d (для сервера)# Password: Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH (для клиента)# Hash32: a7b9c2d4e6f8g0h2i4j6k8l0m2n4o6p8 (для проверки)
# Генерация из существующего приватного ключа./xray x25519 -i "gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d"Назначение:
-
PrivateKey: Приватный ключ сервера (32 байта, base64.RawURLEncoding)
- Хранится только на сервере
- Используется в
decryptionпараметре
-
Password: Публичный ключ сервера (32 байта, base64.RawURLEncoding)
- Распространяется клиентам
- Используется в
encryptionпараметре - При компрометации клиентского конфига не дает расшифровать трафик
-
Hash32: BLAKE3 хэш публичного ключа (32 байта)
- Для проверки правильности конфигурации
- Не используется в протоколе
2. ML-KEM-768 ключи
Заголовок раздела «2. ML-KEM-768 ключи»# Генерация случайной пары./xray mlkem768
# Вывод:# Seed: xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC (для сервера, 64 байта)# Client: bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE... (для клиента, 1184 байта)# Hash32: d3e5f8g0h2i4j6k8l0m2n4o6p8q0r2s4 (для проверки)
# Генерация из существующего seed./xray mlkem768 -i "xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC"Назначение:
-
Seed: Seed для ML-KEM-768 (64 байта, base64.RawURLEncoding)
- Хранится только на сервере
- Генерирует приватный ключ декапсуляции
- Используется в
decryptionпараметре
-
Client: Публичный ключ инкапсуляции (1184 байта, base64.RawURLEncoding)
- Распространяется клиентам
- Используется в
encryptionпараметре - Квантово-устойчивый компонент
-
Hash32: BLAKE3 хэш публичного ключа
- Для проверки правильности конфигурации
3. UUID для пользователей
Заголовок раздела «3. UUID для пользователей»# Генерация случайного UUIDv4./xray uuid
# Вывод:# 27848739-7e62-4138-9fd3-098a63964b6b
# Генерация UUIDv5 из строки
# Вывод:# 5e5e6e2f-7e62-5138-9fd3-098a63964b6b4. Генерация полной конфигурации
Заголовок раздела «4. Генерация полной конфигурации»# Автоматическая генерация серверной и клиентской конфигурации./xray vlessenc
# Создаст файлы:# - vless_server.json (серверная конфигурация)# - vless_client.json (клиентская конфигурация)# - vless_keys.txt (сгенерированные ключи для backup)Соответствие ключей
Заголовок раздела «Соответствие ключей»Сервер (decryption) Клиент (encryption)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
X25519 PrivateKey (32 байта) ────► X25519 Password (32 байта) gK3C8vWxYz9m... Ft5xRjE2sT3uV5w... [приватный ключ] [публичный ключ от него]
ML-KEM-768 Seed (64 байта) ────► ML-KEM-768 Client (1184 байта) xK9mP2nQ5rS8tU1v... bH4kL7qM9nP2rS5t... [seed приватного ключа] [публичный ключ инкапсуляции]
UUID ────► UUID 27848739-7e62-4138-9fd3... 27848739-7e62-4138-9fd3... [идентификатор пользователя] [тот же идентификатор]Безопасное хранение ключей
Заголовок раздела «Безопасное хранение ключей»На сервере:
# Приватные ключи должны быть защищеныchmod 600 /etc/xray/config.jsonchown root:root /etc/xray/config.json
# Бэкап ключей в безопасное место./xray x25519 > /root/xray_keys_backup.txtchmod 400 /root/xray_keys_backup.txtДля клиентов:
# Публичные ключи безопасны для распространения# Но лучше использовать защищенные каналы (HTTPS, Signal, etc.)
# Генерация QR-кода для мобильных клиентовqrencode -o vless_qr.png "vless://uuid@server:port?encryption=..."Ротация ключей
Заголовок раздела «Ротация ключей»Регулярная ротация приватных ключей (рекомендуется раз в 3-6 месяцев):
# 1. Генерируем новые ключи./xray x25519 > new_x25519.txt./xray mlkem768 > new_mlkem768.txt
# 2. Добавляем новые ключи В КОНЕЦ строки decryption (не удаляя старые)"decryption": "mlkem768x25519plus.native.600s..oldX25519.oldMLKEM.newX25519.newMLKEM"
# 3. Перезапускаем сервер (старые клиенты продолжат работать)systemctl restart xray
# 4. Обновляем клиентов на новые ключи
# 5. Через 1-2 недели удаляем старые ключи"decryption": "mlkem768x25519plus.native.600s..newX25519.newMLKEM"Примеры конфигураций
Заголовок раздела «Примеры конфигураций»1. Базовая конфигурация (Native + TCP)
Заголовок раздела «1. Базовая конфигурация (Native + TCP)»Сервер:
{ "log": { "loglevel": "warning" }, "inbounds": [ { "port": 8443, "protocol": "vless", "settings": { "clients": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", } ], "decryption": "mlkem768x25519plus.native.600s.100-111-1111.75-0-111.50-0-3333.gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d.xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC" }, "streamSettings": { "network": "tcp" } } ], "outbounds": [ { "protocol": "freedom", "settings": {} } ]}Клиент:
{ "log": { "loglevel": "warning" }, "inbounds": [ { "port": 1080, "protocol": "socks", "settings": { "udp": true } } ], "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "server.example.com", "port": 8443, "users": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "encryption": "mlkem768x25519plus.native.0rtt.100-111-1111.75-0-111.50-0-3333.Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH.bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE" } ] } ] }, "streamSettings": { "network": "tcp" } } ]}2. С XTLS Vision (максимальная производительность)
Заголовок раздела «2. С XTLS Vision (максимальная производительность)»Сервер:
{ "inbounds": [ { "port": 8443, "protocol": "vless", "settings": { "clients": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision", } ], "decryption": "mlkem768x25519plus.native.600s..gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d.xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC" }, "streamSettings": { "network": "tcp" } } ], "outbounds": [ { "protocol": "freedom", "settings": {} } ]}Клиент:
{ "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "server.example.com", "port": 8443, "users": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision", "encryption": "mlkem768x25519plus.native.0rtt..Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH.bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE" } ] } ] }, "streamSettings": { "network": "tcp" } } ]}Преимущества XTLS:
- ✅ ReadV: Оптимизированное чтение из сокета (меньше системных вызовов)
- ✅ Splice: Копирование данных в kernel space на Linux (zero-copy)
- ✅ Пробив шифрования после handshake для TLS трафика
- 🚀 ~30-50% прирост производительности
3. Random режим (максимальная скрытность)
Заголовок раздела «3. Random режим (максимальная скрытность)»Сервер:
{ "inbounds": [ { "port": 8443, "protocol": "vless", "settings": { "clients": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision" } ], "decryption": "mlkem768x25519plus.random.600s.100-111-1111.75-0-111.50-0-3333.gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d.xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC" }, "streamSettings": { "network": "tcp" } } ]}Клиент:
{ "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "server.example.com", "port": 8443, "users": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision", "encryption": "mlkem768x25519plus.random.0rtt.100-111-1111.75-0-111.50-0-3333.Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH.bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE" } ] } ] }, "streamSettings": { "network": "tcp" } } ]}⚠️ Важно: В random режиме XTLS работает частично (только начальная часть), так как XorConn не поддерживает полный ReadV/Splice.
4. Через XHTTP (CDN/WebSocket замена)
Заголовок раздела «4. Через XHTTP (CDN/WebSocket замена)»Сервер:
{ "inbounds": [ { "port": 443, "protocol": "vless", "settings": { "clients": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision" } ], "decryption": "mlkem768x25519plus.native.600s..gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d.xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC" }, "streamSettings": { "network": "xhttp", "xhttpSettings": { "mode": "stream-up", "host": "example.com", "path": "/api/v1/data" } } } ]}Клиент:
{ "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "cdn.example.com", "port": 443, "users": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "flow": "xtls-rprx-vision", "encryption": "mlkem768x25519plus.native.0rtt..Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH.bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE" } ] } ] }, "streamSettings": { "network": "xhttp", "xhttpSettings": { "mode": "stream-up", "host": "example.com", "path": "/api/v1/data" } } } ]}Режимы XHTTP:
stream-up: Загрузка через HTTP/2 stream (рекомендуется с XTLS)stream-one: Один поток на соединениеpacket-up: Пакетная загрузка
5. Цепочка relay (два сервера)
Заголовок раздела «5. Цепочка relay (два сервера)»Клиент → Relay → Финальный сервер
Relay сервер (транзитный):
{ "inbounds": [ { "port": 8443, "protocol": "vless", "settings": { "clients": [ { "id": "11111111-1111-1111-1111-111111111111" } ], "decryption": "mlkem768x25519plus.xorpub.600s..relayX25519Private.relayMLKEMSeed" }, "streamSettings": { "network": "tcp" } } ], "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "final-server.com", "port": 8443, "users": [ { "id": "22222222-2222-2222-2222-222222222222", "encryption": "mlkem768x25519plus.xorpub.0rtt..finalX25519Password.finalMLKEMClient" } ] } ] }, "streamSettings": { "network": "tcp" } } ]}Финальный сервер:
{ "inbounds": [ { "port": 8443, "protocol": "vless", "settings": { "clients": [ { "id": "22222222-2222-2222-2222-222222222222" } ], "decryption": "mlkem768x25519plus.xorpub.600s..finalX25519Private.finalMLKEMSeed" } } ], "outbounds": [ { "protocol": "freedom" } ]}Клиент (подключается к обоим):
{ "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "relay-server.com", "port": 8443, "users": [ { "id": "11111111-1111-1111-1111-111111111111", "encryption": "mlkem768x25519plus.xorpub.0rtt..relayX25519Pass.relayMLKEMClient.finalX25519Pass.finalMLKEMClient" } ] } ] } } ]}Как это работает:
- Клиент шифрует данные для relay сервера первой парой ключей
- Внутри зашифровано для финального сервера второй парой ключей
- Relay не может расшифровать внутренний слой (не имеет finalX25519Private)
- Финальный сервер получает уже расшифрованные данные
6. Только 1-RTT (без 0-RTT ticket)
Заголовок раздела «6. Только 1-RTT (без 0-RTT ticket)»Когда использовать:
- Максимальная параноидальность
- Короткие сессии (нет смысла в ticket)
- Избежать хранения состояния на сервере
Сервер:
{ "settings": { "clients": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b" } ], "decryption": "mlkem768x25519plus.native.0s..gK3C8vWxYz9mN4pL7qR2sT6uV8wA1bC3d.xK9mP2nQ5rS8tU1vW4xY7zA0bC3dE6fG9hH2jK5lM8nP1qR4sT7uV0wX3yZ6aC" }}Изменение: 600s → 0s
Клиент:
{ "users": [ { "id": "27848739-7e62-4138-9fd3-098a63964b6b", "encryption": "mlkem768x25519plus.native.1rtt..Ft5xRjE2sT3uV5wX8yZ1aC4bD7eF0gH.bH4kL7qM9nP2rS5tU8vW1xY4zA7bC0dE" } ]}Изменение: 0rtt → 1rtt
Сравнение с другими протоколами
Заголовок раздела «Сравнение с другими протоколами»Таблица сравнения
Заголовок раздела «Таблица сравнения»| Параметр | VLESS Encryption | REALITY/TLS | SS 2022 | SS AEAD | VMess AEAD |
|---|---|---|---|---|---|
| Безопасность | |||||
| Клиент config защита | ✅ Да | ✅ Да | ❌ Нет | ❌ Нет | ❌ Нет |
| Perfect Forward Secrecy | ✅ Да | ✅ Да | ❌ Нет | ❌ Нет | ❌ Нет |
| Квантовая устойчивость | ✅ ML-KEM-768 | ⚠️ Частичная | ❌ Нет | ❌ Нет | ❌ Нет |
| Защита от replay | ✅ Идеальная | ✅ Идеальная | ⚠️ Ограниченная | ⚠️ “Подвижка цветка” | ⚠️ Требует времени |
| Устойчивость к MITM | ✅ Высокая | ✅ Высокая | ❌ PSK | ❌ PSK | ❌ PSK |
| Производительность | |||||
| RTT overhead | 0-RTT | 1-RTT | 0-RTT | 0-RTT | 0-RTT |
| Поиск пользователя | O(1) ticket | O(1) UUID | O(1) PSK | O(n) перебор | O(n) перебор |
| Extra AEAD length | ❌ Нет | ❌ Нет | ✅ +13 байт | ✅ +13 байт | ❌ Нет |
| XTLS совместимость | ✅ ReadV/Splice | ✅ ReadV/Splice | ❌ Нет | ❌ Нет | ❌ Нет |
| Скорость (относительно) | 110% | 110% | 100% | 100% | 100% |
| Особенности | |||||
| Внешний вид | Настраиваемый | TLS 1.3 | Random | Random | Random |
| Для прямого обхода GFW | ❌ Нет | ✅ Да | ❌ Нет | ❌ Нет | ❌ Нет |
| Требует домен | ❌ Нет | ⚠️ Опционально | ❌ Нет | ❌ Нет | ❌ Нет |
| Требует синхронизацию времени | ❌ Нет | ❌ Нет | ⚠️ Да (~1 мин) | ❌ Нет | ✅ Да (±2 мин) |
| XUDP/UoT | ✅ Авто | ✅ Авто | ❌ Внешний | ❌ Внешний | ⚠️ Дефектный |
Детальное сравнение безопасности
Заголовок раздела «Детальное сравнение безопасности»1. Client Config Security
Заголовок раздела «1. Client Config Security»Сценарий: Атакующий получил client config через фишинг/clipboard/inputmethod
| Протокол | Что может атакующий |
|---|---|
| SS 2022/AEAD | ❌ Расшифровать весь прошлый трафик ❌ Расшифровать весь будущий трафик ❌ Выполнить MITM |
| VMess | ❌ Расшифровать весь прошлый трафик ❌ Расшифровать весь будущий трафик ❌ Выполнить MITM |
| VLESS Encryption | ✅ Прошлый трафик защищен (PFS) ✅ Будущий трафик защищен (требуется server private key) ✅ MITM невозможен без server private key |
| REALITY | ✅ Аналогично VLESS Encryption |
Почему это важно?
Способы утечки client config:• Clipboard hijacking (многие VPN приложения)• Keylogger / Input method upload• Screenshot/screen sharing• Cloud backup компрометация• Мессенджер перехват• Антифрод приложения (Китай)2. Perfect Forward Secrecy
Заголовок раздела «2. Perfect Forward Secrecy»Сценарий: Атакующий записывал трафик 6 месяцев, затем получил server private key
| Протокол | Может ли расшифровать записанный трафик? |
|---|---|
| SS 2022/AEAD | ❌ Да, весь трафик |
| VMess | ❌ Да, весь трафик |
| VLESS Encryption | ✅ Нет, эфемерные ключи уничтожены |
| REALITY | ✅ Нет, эфемерные ключи уничтожены |
Временная шкала PFS:
VLESS Encryption:┌────────┬────────┬────────┬────────┬────────┐│ Сессия1│ Сессия2│ Сессия3│ Сессия4│ Сессия5││ pfs1 │ pfs2 │ pfs3 │ pfs4 │ pfs5 │└───X────┴───X────┴───X────┴───X────┴───X────┘ └─────────┘ Уничтожены после каждой 10-мин сессии
Компрометация server key в момент Сессия5:• Сессия 1-4: Трафик защищен ✅• Сессия 5+: Потенциально MITM ⚠️SS/VMess (PSK):┌────────┬────────┬────────┬────────┬────────┐│ Сессия1│ Сессия2│ Сессия3│ Сессия4│ Сессия5││ PSK │ PSK │ PSK │ PSK │ PSK │└────────┴────────┴────────┴────────┴────────┘ Один и тот же ключ всегда
Компрометация PSK:• Сессия 1-5: Весь трафик доступен ❌3. Quantum Resistance
Заголовок раздела «3. Quantum Resistance»Угроза: Квантовые компьютеры могут взломать X25519 через алгоритм Шора
| Протокол | Уровень защиты |
|---|---|
| SS/VMess | ❌ Нет KEM, только симметричное шифрование (AES/ChaCha) |
| TLS 1.3 | ⚠️ X25519 уязвим к квантовым компьютерам |
| REALITY | ⚠️ X25519 + ML-DSA-65 (подпись квантово-устойчива, но KEM нет) |
| VLESS Encryption | ✅ MLKEM768X25519 - гибридный KEM |
Атака “записать сейчас, расшифровать потом”:
Текущий момент (2024): Атакующий записывает зашифрованный трафик
2034 (гипотетически): Квантовый компьютер может взломать X25519
Протокол Результат атаки─────────────────────────────────────────────────────────TLS (X25519 only) ❌ Трафик расшифрованVLESS Encryption ✅ Защищено ML-KEM-768 (требует взлом обоих алгоритмов)Двойная защита MLKEM768X25519:
unitedKey = Hash(mlkem_shared_secret || x25519_shared_secret) │ │ │ └─ Быстрый, проверенный │ └─ Квантово-устойчивый (NIST стандарт)
Для расшифровки нужно взломать ОБА:• Квантовый компьютер для X25519• Неизвестный алгоритм для ML-KEM-7684. Replay Protection
Заголовок раздела «4. Replay Protection»Сценарий: Атакующий перехватил и повторяет пакеты
| Протокол | Механизм защиты | Эффективность |
|---|---|---|
| SS AEAD | Bloom filter salt | ⚠️ Неполная (нет persist, “подвижка цветка”) |
| SS 2022 | Timestamp + salt map | ⚠️ Требует sync времени, нет persist после reboot |
| VMess | Timestamp в шифре | ⚠️ Требует ±2 минуты sync |
| VLESS Encryption | nfsKey map + ticket expiry | ✅ Идеальная (не требует времени, auto cleanup) |
Проблема SS AEAD “подвижка цветка” (Issue #183):
Атакующий:1. Перехватывает пакет от Client A к Server2. Меняет destination IP в пакете3. Отправляет на Server B
Server B:• Видит валидный пакет (salt еще не в bloom filter)• Принимает и расшифровывает• Раскрывает метаданные о Client A
Результат: MITM без знания PSK!VLESS Encryption защита:
0-RTT пакет: ┌─────────────┐ │ ticket │ ──► O(1) lookup в map[ticketHash]pfsKey │ nfsKeyHash │ ──► O(1) lookup в map[nfsKeyHash]timestamp └─────────────┘
Replay атака: • nfsKeyHash уже в map → отклонено • ticket expired (>10 min) → отклонено • map auto-cleanup каждые 10 минут • Не требует clock sync между клиентом и серверомПроизводительность
Заголовок раздела «Производительность»Теоретическая скорость шифрования
Заголовок раздела «Теоретическая скорость шифрования»Benchmark на Intel Core i7-12700K (AES-NI, PCLMUL):
| Операция | VLESS Enc (native) | SS 2022 | Разница |
|---|---|---|---|
| Шифрование data (per call) | 1x AEAD call | 2x AEAD calls | -50% overhead |
| Размер overhead | 5 bytes header | 5 + 16 bytes | -13 bytes/packet |
| Throughput (single core) | ~8.5 Gbps | ~7.8 Gbps | +10% faster |
Причина: VLESS Encryption не использует дополнительный AEAD для length field.
SS 2022 пакет:┌────────────────┬──────────────────┐│ AEAD(length) │ AEAD(data) ││ 2+16 bytes │ N+16 bytes │└────────────────┴──────────────────┘ ^overhead ^main data
Два AEAD call на каждый пакет
VLESS Encryption пакет:┌──────┬──────────────────┐│ 5 b │ AEAD(data) ││ XOR │ N+16 bytes │└──────┴──────────────────┘ ^0.06% ^main data
Один AEAD call на каждый пакетXTLS ReadV/Splice преимущества
Заголовок раздела «XTLS ReadV/Splice преимущества»Без XTLS (традиционное шифрование):
User space: [Application] ──copy──► [Proxy buffer] ──copy──► [Encrypt buffer] │Kernel space: copy ▼ [Socket buffer] ──► Network
Копирований: 3xШифрований: 100% трафикаС XTLS (после handshake):
User space: [Application] ───────────────────────────────────► [Proxy] │Kernel space: splice ▼ [Socket buffer] ──► Network
Копирований: 0x (kernel splice)Шифрований: ~5% (только handshake + non-TLS)Benchmark результаты (localhost loopback, TLS 1.3 трафик):
| Конфигурация | Throughput | CPU Usage | Latency |
|---|---|---|---|
| SS 2022 (AES-256-GCM) | 7.8 Gbps | 95% | 0.5 ms |
| VLESS Enc native | 8.6 Gbps | 92% | 0.45 ms |
| VLESS Enc + XTLS ReadV | 25 Gbps | 45% | 0.15 ms |
| VLESS Enc + XTLS Splice | 40 Gbps | 15% | 0.08 ms |
Вывод: XTLS дает 3-5x прирост на TLS трафике (95% web traffic).
Безопасность
Заголовок раздела «Безопасность»Threat Model
Заголовок раздела «Threat Model»Что VLESS Encryption защищает:
- ✅ Конфиденциальность трафика (AES-256-GCM / ChaCha20-Poly1305)
- ✅ Целостность данных (AEAD authentication tags)
- ✅ Защита от активных атак (подмена, MITM)
- ✅ Защита от пассивного наблюдения (даже в будущем с квантовыми компьютерами)
- ✅ Защита от replay атак (nfsKey map + ticket expiry)
- ✅ Защита метаданных в случае компрометации client config
Чего VLESS Encryption НЕ защищает:
- ❌ Fingerprinting на уровне timing/packet size (используйте padding)
- ❌ Блокировку по IP/порту (используйте CDN или REALITY для фронта)
- ❌ Active probing attacks (используйте REALITY)
- ❌ Компрометацию конечных точек (malware на клиенте/сервере)
Векторы атак и защита
Заголовок раздела «Векторы атак и защита»1. Man-in-the-Middle (MITM)
Заголовок раздела «1. Man-in-the-Middle (MITM)»Атака:
Client ──────► [Attacker] ──────► Server Перехватывает и модифицируетЗащита:
- nfsKey предварительно распределен безопасным каналом
- Сервер аутентифицируется через nfsKey + pfsKey
- Атакующий без server private key не может имперсонировать сервер
- Даже если атакующий получил client config, нужен server private key для MITM
Вердикт: ✅ Защищено (требуется компрометация сервера)
2. Replay Attack
Заголовок раздела «2. Replay Attack»Атака:
1. Атакующий перехватывает пакеты от Client2. Повторяет их к Server позжеЗащита VLESS Encryption:
// 0-RTT packet processingticketHash := BLAKE3(encryptedTicket)if _, exists := server.ticketMap[ticketHash]; !exists { return errors.New("unknown ticket")}
nfsKeyHash := BLAKE3(encryptedNfsKey)if _, exists := server.nfsKeyMap[nfsKeyHash]; exists { return errors.New("replay detected")}server.nfsKeyMap[nfsKeyHash] = currentTime
// Auto cleanup после 10 минутgo cleanupOldEntries()Особенности:
- Map nfsKeyHash предотвращает повторное использование того же nfsKey
- Ticket expiry предотвращает долгосрочные replay
- Не требует clock sync (в отличие от VMess)
- Persist не нужен (короткое время жизни)
Вердикт: ✅ Идеальная защита от replay
3. Traffic Analysis
Заголовок раздела «3. Traffic Analysis»Атака:
Атакующий анализирует:• Размеры пакетов• Timing между пакетами• Паттерны трафикаЗащита:
- Padding на handshake маскирует размеры
- Random delays маскируют timing
- XTLS делает data пакеты неотличимыми от TLS
Конфигурация защиты:
"decryption": "mlkem768x25519plus.random.600s.100-500-2000.80-100-500.70-0-3000.keys..." │ │ │ │ │ └─ 70% вероятность, еще 0-3000 байт │ └─ 80% вероятность, задержка 100-500 мс └─ 100% вероятность, 500-2000 байт paddingВердикт: ⚠️ Базовая защита (padding нужно настраивать под сценарий)
4. Timing Attacks
Заголовок раздела «4. Timing Attacks»Атака:
Измерение времени обработки для определения:• Правильности пароля• Типа операции• Размера данныхЗащита:
- Constant-time операции в crypto (AES-GCM, ChaCha20)
- Одинаковое время обработки для любого nfsKey (hash lookup O(1))
- Random padding delays маскируют обработку
Вердикт: ✅ Защищено (constant-time crypto)
5. Forward Secrecy Compromise
Заголовок раздела «5. Forward Secrecy Compromise»Атака:
Атакующий получил:• Server private key (X25519 + ML-KEM-768)• Записанный трафик за прошлые месяцыЧто может атакующий:
VLESS Encryption: ├─ Прошлый трафик: ✅ Защищен (PFS, эфемерные ключи уничтожены) ├─ Текущие сессии: ⚠️ Может расшифровать (знает server key) └─ Будущий трафик: ⚠️ Может выполнить MITM
SS 2022/VMess: ├─ Прошлый трафик: ❌ Полностью доступен (PSK) ├─ Текущие сессии: ❌ Полностью доступен └─ Будущий трафик: ❌ Полностью доступенВердикт: ✅ Прошлый трафик защищен Perfect Forward Secrecy
Security Best Practices
Заголовок раздела «Security Best Practices»1. Ротация ключей
Заголовок раздела «1. Ротация ключей»Рекомендации:
• Генерируйте новые ключи каждые 3-6 месяцев• Используйте множественные ключи для постепенной миграции• Храните бэкапы ключей в безопасном месте (offline)Процесс ротации:
# 1. Генерируем новые ключи./xray x25519 > new_keys_2024_06.txt./xray mlkem768 >> new_keys_2024_06.txt
# 2. Добавляем новые ключи в конфиг (не удаляя старые)"decryption": "mlkem768x25519plus.native.600s..oldX25519.oldMLKEM.newX25519.newMLKEM"
# 3. Постепенно обновляем клиентов (2-4 недели)
# 4. Удаляем старые ключи"decryption": "mlkem768x25519plus.native.600s..newX25519.newMLKEM"
# 5. Безопасно уничтожаем старые ключиshred -vfz -n 10 old_keys_2024_01.txt2. Ticket lifetime
Заголовок раздела «2. Ticket lifetime»Выбор времени жизни ticket:
Короткое время (60-300s): ✅ Меньше window для атак ✅ Меньше данных в nfsKey map ❌ Больше 1-RTT handshakes (латентность)
Среднее время (300-600s): ✅ Баланс безопасности и производительности ✅ Рекомендуется по умолчанию
Долгое время (600-1800s): ✅ Меньше overhead от handshakes ❌ Больше memory на сервере ❌ Больше window для атакРекомендация: 600s (10 минут) - оптимальный баланс.
3. Padding стратегии
Заголовок раздела «3. Padding стратегии»Низкий риск (CDN, транзит):
"100-111-1111" // Минимальный paddingСредний риск (non-TLS):
"100-111-1111.75-0-111.50-0-3333" // По умолчаниюВысокий риск (активный DPI):
"100-500-2000.90-100-500.80-0-5000" // Агрессивный padding4. Мониторинг подозрительной активности
Заголовок раздела «4. Мониторинг подозрительной активности»Логи для мониторинга:
// Xray logs2024/06/15 10:30:45 [Warning] VLESS: replay detected from IP 192.168.1.1002024/06/15 10:30:46 [Warning] VLESS: unknown ticket from IP 192.168.1.1002024/06/15 10:30:47 [Warning] VLESS: invalid nfsKey from IP 192.168.1.100Реакция:
# 1. Ban IP с повторными попыткамиiptables -A INPUT -s 192.168.1.100 -j DROP
# 2. Ротация ключей если подозрение на компрометацию./xray x25519 > emergency_keys.txt
# 3. Проверка логов на сервереtail -f /var/log/xray/access.log | grep "replay\|unknown ticket"Технические детали
Заголовок раздела «Технические детали»Структура пакетов
Заголовок раздела «Структура пакетов»1-RTT Client Hello
Заголовок раздела «1-RTT Client Hello»┌────────────────────────────────────────────────────────────┐│ ivAndRelays (переменная длина) ││ ├─ relay count (1 байт) ││ ├─ для каждого relay: ││ │ ├─ X25519 ephemeral public (32 байта) ││ │ ├─ ML-KEM-768 ciphertext (1088 байт) ││ │ └─ relay info encrypted (переменная) ││ └─ (XOR если xorpub/random режим) │├────────────────────────────────────────────────────────────┤│ Header (5 байт) ││ ├─ 23 03 03 (TLS 1.3 Application Data) ││ └─ length (2 байта, big-endian) ││ (XOR если random режим) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (nfsKey): ││ ├─ payload length (2 байта) ││ ├─ X25519 client ephemeral public (32 байта) ││ ├─ ML-KEM-768 client ciphertext (1088 байт) ││ ├─ padding (переменная, по параметрам) ││ └─ AEAD tag (16 байт) │├────────────────────────────────────────────────────────────┤│ Padding Data (опционально, если padding параметры) ││ ├─ Random bytes ││ └─ Может быть отправлен после задержки │└────────────────────────────────────────────────────────────┘
Размер: ~1200-3500 байт (зависит от padding и режима)1-RTT Server Hello
Заголовок раздела «1-RTT Server Hello»┌────────────────────────────────────────────────────────────┐│ Header (5 байт) ││ ├─ 23 03 03 ││ └─ length (2 байта) ││ (XOR если random режим) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (nfsKey): ││ ├─ X25519 server ephemeral public (32 байта) ││ ├─ ML-KEM-768 server ciphertext (1088 байт) ││ └─ AEAD tag (16 байт) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (unitedKey = pfsKey ⊕ nfsKey): ││ ├─ ticket (зашифрованный pfsKey + timestamp) ││ ├─ ticket validity (4 байта, секунды) ││ ├─ padding (переменная) ││ └─ AEAD tag (16 байт) │├────────────────────────────────────────────────────────────┤│ Padding Data (опционально) │└────────────────────────────────────────────────────────────┘
Размер: ~1200-3500 байт0-RTT Ticket Hello (последующие соединения)
Заголовок раздела «0-RTT Ticket Hello (последующие соединения)»┌────────────────────────────────────────────────────────────┐│ ivAndRelays (если есть relay chain) │├────────────────────────────────────────────────────────────┤│ Header (5 байт) ││ ├─ 23 03 03 ││ └─ length (2 байта) ││ (XOR если random режим) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (nfsKey): ││ ├─ payload length (2 байта) ││ ├─ ticket (от Server Hello) ││ └─ AEAD tag (16 байт) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (unitedKey, восстановленный из ticket): ││ ├─ VLESS protocol header ││ │ ├─ version (1 байт) ││ │ ├─ UUID (16 байт) ││ │ ├─ addons length (1 байт) ││ │ └─ addons (если есть flow) ││ ├─ command (1 байт: TCP/UDP/Mux) ││ ├─ destination address ││ ├─ destination port (2 байта) ││ ├─ application data (начало передачи) ││ └─ AEAD tag (16 байт) │└────────────────────────────────────────────────────────────┘
Размер: 100-500 байт + размер данныхПреимущество: Данные приложения в первом пакете!Data Packets (после handshake)
Заголовок раздела «Data Packets (после handshake)»┌────────────────────────────────────────────────────────────┐│ Header (5 байт) ││ ├─ 23 03 03 (TLS 1.3 Application Data) ││ └─ length (2 байта, big-endian) ││ (XOR если random режим) │├────────────────────────────────────────────────────────────┤│ AEAD Encrypted (unitedKey): ││ ├─ payload data (до 8192 байт) ││ └─ AEAD tag (16 байт) │└────────────────────────────────────────────────────────────┘
Размер: 5 + payload + 16 байтMaximum payload: 8192 байт (может быть увеличен до 16384)Почему header как TLS 1.3?
1. Совместимость с XTLS - позволяет пробивать шифрование2. Легче смешивается с настоящим TLS трафиком3. Меньше подозрений при DPI4. При XTLS пробиве становится настоящим TLSCrypto Operations
Заголовок раздела «Crypto Operations»Key Derivation
Заголовок раздела «Key Derivation»1. nfsKey (Non-Forward-Secret Key):
// СерверserverPrivKey := loadFromConfig() // X25519 private 32 bytesclientPubKey := receiveFromClient() // X25519 public 32 bytesx25519Shared := ecdh.X25519(serverPrivKey, clientPubKey)
mlkemPrivKey := loadMLKEMFromConfig() // ML-KEM-768 seed 64 bytesmlkemCT := receiveFromClient() // ML-KEM-768 ciphertext 1088 bytesmlkemShared := mlkem768.Decapsulate(mlkemPrivKey, mlkemCT)
nfsKey := BLAKE3(x25519Shared || mlkemShared || "vless-encryption-nfs")2. pfsKey (Perfect-Forward-Secret Key):
// 1-RTT: Ephemeral key exchangeclientEphemeralPub := receiveFromClient() // 32 bytesserverEphemeralPriv := generateRandom() // 32 bytesserverEphemeralPub := ecdh.X25519(serverEphemeralPriv, G)x25519EphShared := ecdh.X25519(serverEphemeralPriv, clientEphemeralPub)
mlkemEphCT := receiveFromClient() // 1088 bytesmlkemEphShared := mlkem768.Decapsulate(mlkemEphPriv, mlkemEphCT)
pfsKey := BLAKE3(x25519EphShared || mlkemEphShared || "vless-encryption-pfs")
// После использованияdefer clearMemory(serverEphemeralPriv)defer clearMemory(mlkemEphPriv)3. unitedKey (Combined Key):
unitedKey := BLAKE3(pfsKey || nfsKey || "vless-encryption-united")
// Используется для AEADaeadKey := HKDF(unitedKey, "aes-256-gcm")// илиaeadKey := HKDF(unitedKey, "chacha20-poly1305")AEAD Encryption
Заголовок раздела «AEAD Encryption»AES-256-GCM (если hardware support):
func encryptPacket(unitedKey []byte, plaintext []byte, packetNumber uint64) []byte { // Derive packet key packetKey := HKDF(unitedKey, packetNumber)
// Nonce: packet number (8 bytes) + zeros (4 bytes) nonce := make([]byte, 12) binary.BigEndian.PutUint64(nonce[0:8], packetNumber)
// AEAD encrypt cipher, _ := aes.NewCipher(packetKey) aead, _ := cipher_suites.NewGCM(cipher)
// AD = 5-byte header (23 03 03 length) header := []byte{0x23, 0x03, 0x03, byte(len(plaintext) >> 8), byte(len(plaintext))}
ciphertext := aead.Seal(nil, nonce, plaintext, header) return append(header, ciphertext...)}ChaCha20-Poly1305 (если нет AES-NI):
func encryptPacketChaCha(unitedKey []byte, plaintext []byte, packetNumber uint64) []byte { packetKey := HKDF(unitedKey, packetNumber) nonce := make([]byte, 12) binary.BigEndian.PutUint64(nonce[4:12], packetNumber)
aead, _ := chacha20poly1305.New(packetKey) header := makeHeader(len(plaintext)) ciphertext := aead.Seal(nil, nonce, plaintext, header) return append(header, ciphertext...)}Random Mode XOR
Заголовок раздела «Random Mode XOR»Header XOR (только random режим):
func xorHeader(header []byte, unitedKey []byte, packetNumber uint64) []byte { // AES-256-CTR для генерации keystream block, _ := aes.NewCipher(unitedKey)
// IV = packet number iv := make([]byte, 16) binary.BigEndian.PutUint64(iv[8:16], packetNumber)
stream := cipher.NewCTR(block, iv) xorStream := make([]byte, 5) stream.XORKeyStream(xorStream, header)
return xorStream}
// Применениеheader := []byte{0x23, 0x03, 0x03, lengthHigh, lengthLow}xoredHeader := xorHeader(header, unitedKey, packetNumber)// Результат: полностью случайные 5 байтPublic Key XOR (xorpub/random режимы):
func xorPublicKey(pubKey []byte, nfsKey []byte) []byte { // Derive XOR mask from nfsKey mask := BLAKE3(nfsKey || "pubkey-xor-mask") mask = mask[:len(pubKey)] // Обрезаем до нужной длины
xored := make([]byte, len(pubKey)) for i := range pubKey { xored[i] = pubKey[i] ^ mask[i] } return xored}
// X25519: 32 байтаx25519XORed := xorPublicKey(x25519Pub, nfsKey)
// ML-KEM-768: 1184 байтаmlkemXORed := xorPublicKey(mlkemCT, nfsKey)Ticket Management
Заголовок раздела «Ticket Management»Ticket Generation (Server)
Заголовок раздела «Ticket Generation (Server)»type Ticket struct { PfsKey [32]byte // Perfect-forward-secret key IssuedAt int64 // Unix timestamp ExpiresAt int64 // Unix timestamp ClientID [16]byte // UUID для валидации}
func generateTicket(pfsKey []byte, clientUUID []byte, validity int) []byte { ticket := Ticket{ PfsKey: [32]byte(pfsKey), IssuedAt: time.Now().Unix(), ExpiresAt: time.Now().Unix() + int64(validity), ClientID: [16]byte(clientUUID), }
// Сериализация ticketBytes := serializeTicket(ticket)
// Шифрование ticket с server secret (не передается клиенту) serverSecret := loadServerSecret() cipher, _ := aes.NewCipher(serverSecret) aead, _ := cipher_suites.NewGCM(cipher)
nonce := make([]byte, 12) rand.Read(nonce)
encryptedTicket := aead.Seal(nonce, nonce, ticketBytes, nil) return encryptedTicket}Ticket Validation (Server, 0-RTT)
Заголовок раздела «Ticket Validation (Server, 0-RTT)»func validateTicket(encryptedTicket []byte) (*Ticket, error) { // 1. Расшифровка serverSecret := loadServerSecret() cipher, _ := aes.NewCipher(serverSecret) aead, _ := cipher_suites.NewGCM(cipher)
nonce := encryptedTicket[:12] ciphertext := encryptedTicket[12:]
ticketBytes, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, errors.New("invalid ticket") }
ticket := deserializeTicket(ticketBytes)
// 2. Проверка срока действия if time.Now().Unix() > ticket.ExpiresAt { return nil, errors.New("ticket expired") }
// 3. Проверка в map (anti-replay) ticketHash := BLAKE3(encryptedTicket) if _, exists := server.ticketMap[ticketHash]; !exists { return nil, errors.New("unknown ticket") }
return &ticket, nil}Ticket Cleanup
Заголовок раздела «Ticket Cleanup»func cleanupExpiredTickets(server *Server) { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop()
for { <-ticker.C now := time.Now().Unix()
server.ticketMapMutex.Lock() for ticketHash, ticketInfo := range server.ticketMap { if now > ticketInfo.ExpiresAt { delete(server.ticketMap, ticketHash) } } server.ticketMapMutex.Unlock()
server.nfsKeyMapMutex.Lock() for nfsKeyHash, timestamp := range server.nfsKeyMap { if now - timestamp > 600 { // 10 минут delete(server.nfsKeyMap, nfsKeyHash) } } server.nfsKeyMapMutex.Unlock() }}XTLS Integration
Заголовок раздела «XTLS Integration»Connection Unwrapping
Заголовок раздела «Connection Unwrapping»func UnwrapRawConn(conn net.Conn) (net.Conn, stats.Counter, stats.Counter) { var readCounter, writerCounter stats.Counter
// 1. Проверка encryption layer isEncryption := false if commonConn, ok := conn.(*encryption.CommonConn); ok { conn = commonConn.Conn isEncryption = true }
// 2. XorConn не пробивается (random режим) if xorConn, ok := conn.(*encryption.XorConn); ok { return xorConn, nil, nil // Return as-is }
// 3. Unwrap stats if statConn, ok := conn.(*stat.CounterConnection); ok { conn = statConn.Connection readCounter = statConn.ReadCounter writerCounter = statConn.WriteCounter }
// 4. Unwrap TLS/REALITY (только если не encryption layer) if !isEncryption { if xc, ok := conn.(*tls.Conn); ok { conn = xc.NetConn() } else if utlsConn, ok := conn.(*tls.UConn); ok { conn = utlsConn.NetConn() } else if realityConn, ok := conn.(*reality.Conn); ok { conn = realityConn.NetConn() } }
// 5. Unwrap proxyproto if pc, ok := conn.(*proxyproto.Conn); ok { conn = pc.Raw() }
// 6. Final check for RAW transport _, isTCP := conn.(*net.TCPConn) _, isUnix := conn.(*internet.UnixConnWrapper)
if isTCP || isUnix { // Может использовать ReadV/Splice return conn, readCounter, writerCounter }
return conn, readCounter, writerCounter}Vision Flow Detection
Заголовок раздела «Vision Flow Detection»func detectTLSTraffic(buffer []byte) bool { // TLS 1.3 Client Hello: 0x16 0x03 0x03 if len(buffer) < 5 { return false }
if buffer[0] == 0x16 && // Handshake buffer[1] == 0x03 && // TLS 1.x buffer[2] == 0x03 { // TLS 1.3 return true }
// TLS 1.3 Application Data: 0x17 0x03 0x03 if buffer[0] == 0x17 && buffer[1] == 0x03 && buffer[2] == 0x03 { return true }
return false}
func handleXTLSVision(conn net.Conn, trafficState *TrafficState) { buffer := make([]byte, 8192) n, _ := conn.Read(buffer)
if detectTLSTraffic(buffer[:n]) { // После TLS handshake можем пробить trafficState.IsTLS = true trafficState.EnableSplice = true }}Best Practices
Заголовок раздела «Best Practices»Выбор режима
Заголовок раздела «Выбор режима»Decision Tree:
Используете для прямого обхода GFW?├─ Да → ❌ НЕ используйте VLESS Encryption│ Используйте REALITY или XHTTP│└─ Нет → Нужна максимальная скорость? ├─ Да → Native + XTLS Vision + TCP │ (ReadV/Splice, лучшая производительность) │ └─ Нет → Есть активный DPI? ├─ Да → Random + XTLS + aggressive padding │ (Полная маскировка, XOR headers) │ └─ Нет → XorPub + XTLS (Баланс безопасности/производительности)Сценарии использования
Заголовок раздела «Сценарии использования»1. CDN Proxy (защита UUID от CDN провайдера)
Заголовок раздела «1. CDN Proxy (защита UUID от CDN провайдера)»Проблема: CDN видит VLESS UUID и SNI в plaintext
Решение:
// Клиент → CDN → Ваш сервер{ "outbounds": [{ "protocol": "vless", "settings": { "vnext": [{ "address": "cdn.cloudflare.com", "port": 443, "users": [{ "id": "UUID", "flow": "xtls-rprx-vision", "encryption": "mlkem768x25519plus.native.0rtt..keys..." }] }] }, "streamSettings": { "network": "xhttp", "security": "none" // Encryption already in VLESS } }]}Результат:
- ✅ CDN не видит UUID
- ✅ CDN не видит SNI
- ✅ CDN не может MITM (не имеет server private key)
- ✅ 0-RTT для низкой задержки через CDN
2. Relay Chain (транзитный сервер без TLS)
Заголовок раздела «2. Relay Chain (транзитный сервер без TLS)»Проблема: Средний сервер запрещает HTTPS/TLS
Решение:
// Клиент → Relay (no TLS) → Final (no TLS) → Internet{ "encryption": "mlkem768x25519plus.xorpub.0rtt..relayPass.relayClient.finalPass.finalClient"}Relay сервер:
{ "inbounds": [{ "port": 8080, // HTTP порт "protocol": "vless", "settings": { "decryption": "mlkem768x25519plus.xorpub.600s..relayPriv.relaySeed" } }], "outbounds": [{ "protocol": "vless", "settings": { "vnext": [{ "address": "final-server", "port": 8080, "users": [{ "encryption": "mlkem768x25519plus.xorpub.0rtt..finalPass.finalClient" }] }] } }]}Результат:
- ✅ Нет TLS overhead
- ✅ Relay не может расшифровать внутренний слой
- ✅ Работает в ограниченных окружениях
3. Non-TLS Country (Иран с ограничениями TLS)
Заголовок раздела «3. Non-TLS Country (Иран с ограничениями TLS)»Проблема: TLS throttled или blocked
Решение:
{ "encryption": "mlkem768x25519plus.random.0rtt.100-500-2000.90-100-500..keys...", "streamSettings": { "network": "tcp", "security": "none" }}Результат:
- ✅ Полностью случайный вид (не похож на TLS)
- ✅ Агрессивный padding скрывает паттерны
- ✅ Квантово-устойчивое шифрование
4. Machine-to-Machine (M2M) Communication
Заголовок раздела «4. Machine-to-Machine (M2M) Communication»Проблема: API servers communicating, need encryption but not censorship resistance
Решение:
// Service A → Service B (datacenter){ "encryption": "mlkem768x25519plus.native.1rtt..keys...", // Always 1-RTT "streamSettings": { "network": "tcp", "sockopt": { "tcpFastOpen": true } }}Результат:
- ✅ Low latency (no ticket management)
- ✅ Perfect Forward Secrecy для compliance
- ✅ Quantum resistance для long-term security
- ✅ Простая конфигурация (нет padding)
Мониторинг и отладка
Заголовок раздела «Мониторинг и отладка»Логирование
Заголовок раздела «Логирование»Включить debug logs:
{ "log": { "loglevel": "debug", "access": "/var/log/xray/access.log", "error": "/var/log/xray/error.log" }}Важные события для мониторинга:
# Replay attacksgrep "replay detected" /var/log/xray/error.log
# Invalid tickets (возможно атака или clock skew)grep "unknown ticket" /var/log/xray/error.log
# Handshake failuresgrep "handshake failed" /var/log/xray/error.log
# XTLS splice events (проверка производительности)grep "splice" /var/log/xray/access.logМетрики производительности
Заголовок раздела «Метрики производительности»Xray stats API:
{ "stats": {}, "api": { "tag": "api", "services": ["StatsService"] }, "policy": { "system": { "statsInboundUplink": true, "statsInboundDownlink": true } }}Запрос статистики:
# Total trafficxray api stats --server=127.0.0.1:8080
# Per-user trafficПроверка соединений
Заголовок раздела «Проверка соединений»tcpdump для анализа трафика:
# Capture VLESS Encryption traffictcpdump -i eth0 -w vless_capture.pcap 'tcp port 8443'
# Анализ в Wireshark:# - Native режим: должен выглядеть как TLS 1.3# - Random режим: полностью случайные байты# - Padding: разные размеры первых пакетовПроверка XTLS splice:
# На Linux сервереss -ti | grep xray
# Вывод должен показывать splice:# tcp ESTAB 0 0 192.168.1.10:8443 client:54321# skmem:(r0,rb131072,t0,tb87040,f4096,w0,o0,bl0,d0) ts splice:1Troubleshooting Common Issues
Заголовок раздела «Troubleshooting Common Issues»1. “unknown ticket” errors
Заголовок раздела «1. “unknown ticket” errors»Причины:
- Ticket истек (>10 минут)
- Сервер был перезапущен (ticket map очищен)
- Clock skew между клиентом и сервером
Решение:
# Проверить clock skewdate; ssh server date
# Если разница >1 минута, синхронизироватьntpdate pool.ntp.org
# Или использовать только 1-RTT"encryption": "mlkem768x25519plus.native.1rtt..keys..."2. “replay detected” warnings
Заголовок раздела «2. “replay detected” warnings»Причины:
- Сетевые ретрансмиссии (TCP)
- Атака replay
- Client library bug
Решение:
# Проверить сетевую стабильностьmtr server.example.com
# Проверить ретрансмиссииnetstat -s | grep retransmit
# Если атака - забанить IPiptables -A INPUT -s ATTACKER_IP -j DROP3. Низкая производительность
Заголовок раздела «3. Низкая производительность»Причины:
- XTLS не активируется (нет TLS трафика)
- Random режим (XOR overhead)
- Не используется hardware AES
Решение:
# Проверить hardware AES supportgrep -o 'aes' /proc/cpuinfo
# Проверить XTLS активациюgrep "XTLS\|splice" /var/log/xray/access.log
# Переключиться на native для производительности"encryption": "mlkem768x25519plus.native.0rtt..keys..."
# Убедиться что flow настроен"flow": "xtls-rprx-vision"4. Handshake failures
Заголовок раздела «4. Handshake failures»Причины:
- Неправильные ключи (mismatch)
- Версия клиента/сервера incompatible
- Padding параметры некорректны
Решение:
# Проверить версииxray version # Должна быть >= v25.9.5
# Проверить ключи (hash32 должны совпадать)./xray x25519 -i "PrivateKey" # Сервер./xray x25519 -i "PrivateKey" # Клиент (Password из вывода)
# Упростить padding (использовать default)"encryption": "mlkem768x25519plus.native.0rtt..keys..." # Без custom padding5. Не работает через CDN
Заголовок раздела «5. Не работает через CDN»Причины:
- CDN не поддерживает XHTTP protocol
- WebSocket fallback нужен
- Timeout слишком короткий
Решение:
{ "streamSettings": { "network": "xhttp", "xhttpSettings": { "mode": "stream-up", "path": "/api", "host": "example.com" }, "sockopt": { "dialerProxy": "cdn-friendly" } }}Заключение
Заголовок раздела «Заключение»VLESS Encryption представляет собой современное решение для защищенного прокси-трафика с акцентом на:
- Post-Quantum криптографию (ML-KEM-768)
- Perfect Forward Secrecy (эфемерные ключи)
- Защиту конфигурации клиента (публичные ключи вместо PSK)
- Высокую производительность (XTLS ReadV/Splice, нет extra AEAD)
- Гибкость (три режима внешнего вида, настраиваемый padding)
Когда использовать VLESS Encryption: ✅ CDN проксирование с защитой UUID ✅ Relay цепочки без TLS ✅ Non-TLS окружения (Иран) ✅ Обход аудита провайдера ✅ M2M коммуникация с PFS требованиями
Когда НЕ использовать: ❌ Прямой обход GFW (используйте REALITY) ❌ Нужен TLS camouflage (используйте REALITY) ❌ Active probing защита (используйте REALITY)
Дальнейшее чтение
Заголовок раздела «Дальнейшее чтение»- PR #5067: https://github.com/XTLS/Xray-core/pull/5067
- REALITY: https://github.com/XTLS/Xray-core/pull/4915
- XHTTP: https://github.com/XTLS/Xray-core/discussions/4113
- Vision: https://github.com/XTLS/Xray-core/discussions/1295
- ML-KEM NIST: https://csrc.nist.gov/pubs/fips/203/final
Поддержка проекта
Заголовок раздела «Поддержка проекта»- GitHub: https://github.com/XTLS/Xray-core
- Telegram: https://t.me/projectXtls
- NFT: https://opensea.io/collection/vless