Reality — обман DPI без сертификата

Reality (RPRX, январь 2023) — самый революционный шаг в обходе блокировок за последние 5 лет. Главная идея: не маскироваться под HTTPS, а реально проводить HTTPS-handshake с настоящим чужим сайтом. Только в середине этого handshake клиент и сервер «перехватывают» канал. DPI видит идеальный TLS — потому что он идеальный.

Что узнаешь

1. Проблема, которую решает Reality

До Reality все «маскирующиеся» протоколы (Trojan, VLESS+TLS+WS) имели две слабости:

  1. Нужен настоящий домен и сертификат. Покупка домена, привязка к IP, Let's Encrypt, обновление каждые 90 дней. Каждый «свой» домен в blacklist DPI попадает быстро.
  2. Active probing. DPI может сам подключиться к подозрительному IP и проверить: «а есть ли тут реальный сайт?». Если нет — забанить.

Reality решает оба за раз: SNI указывает на чужой реальный сайт, и сервер Reality, увидев handshake без нужного «приветствия», проксирует handshake на тот самый чужой сайт. Active probe получит ответ настоящего сервера — не от твоего VPN.

2. Как работает Reality — высокоуровневая схема

Reality: процесс установления соединения
Клиент (Xray + Reality) DPI / ТСПУ (видит ВСЁ) Reality-сервер (твой VPS) apple.com (настоящий сайт, dest) ① TCP к IP сервера:443 ② ClientHello, SNI=apple.com DPI: "ок, apple.com — ok" ③ если auth fail → проксирует ClientHello → apple сервер проверяет: расшифровка X25519 KeyShare + valid auth tag? ④ ServerHello (наш, valid TLS 1.3) DPI видит: TLS 1.3 handshake idle ⑤ Certificate apple.com ⑥ кладёт настоящий cert в ответ DPI видит: настоящий apple.com cert! ⑦ Туннель установлен! DPI видит: обычный HTTPS с apple.com
Reality: TLS handshake к чужому сайту, который перехватывает на середине свой сервер

3. Как сервер проверяет «свой/чужой» в первом байте

Это сердце Reality. Никакого пароля в plaintext, никакой явной аутентификации. Используется хитрая схема на X25519:

  1. На сервере сгенерирована пара (server_priv, server_pub). server_pub кладётся в конфиг клиента.
  2. Клиент при handshake генерирует свой ephemeral X25519 e_c. Считает shared = X25519(e_c, server_pub).
  3. Использует shared как ключ для шифрования специального auth-tag, который кладётся в случайное место session_id поля ClientHello (32 байта random, как должно быть). Клиент пишет туда зашифрованный «правильный» магический cookie.
  4. В Key Share extension клиент кладёт свой e_c. Сервер видит его как обычный TLS Key Share — DPI не подозревает.
  5. Сервер получает ClientHello, видит KeyShare, вычисляет shared = X25519(server_priv, e_c), пытается расшифровать session_id. Если magic cookie сошёлся — клиент свой.
  6. Если расшифровка не сошлась (это сторонний запрос, например, active probe DPI) — сервер проксирует ClientHello на dest = apple.com:443 и отдаёт обратно настоящие ответы apple.com. Active probe видит реальный сайт.
Под капотом

Почему это математически невозможно отличить от настоящего TLS

В ClientHello session_id — это произвольные 32 байта, описанные стандартом TLS как «opaque». У реальных браузеров session_id — обычно случайные (или специфический формат). У клиента Reality session_id выглядит как случайный шум (потому что это шифротекст). DPI не может отличить «random» от «зашифрованного random» — это и есть фундамент Reality.

KeyShare X25519 — тоже выглядит как 32 байта random для DPI. Эфемерный pub-key всегда так выглядит. Никакой статистический классификатор не может опознать «не настоящий X25519 KeyShare».

4. ShortIDs — несколько клиентов на одном сервере

Если у тебя 10 пользователей, у каждого свой UUID — как сервер их различает? В Reality для этого есть ShortIDs — короткие (1-8 байт) hex-строки, которые тоже кладутся в зашифрованную часть session_id.

В конфиге сервера:

"shortIds": [
  "",                  // ← пустой = «любой» (на отладке)
  "01ab",              // пользователь 1
  "02cd",              // пользователь 2
  "03ef",              // пользователь 3
  "0a0b0c0d0e0f1011"   // VIP-пользователь, длиннее (8 байт)
]
  

У клиента в конфиге shortId: "01ab" — он его шифрует в session_id. Сервер расшифровал — сравнил с whitelist'ом — пропустил.

5. Какой dest (SNI-цель) выбирать

Это самый важный конфигурационный параметр Reality. К чему предъявляются требования:

Идеальный dest
  1. TLS 1.3 only. Сервер должен поддерживать TLS 1.3 (Reality использует только её для KeyShare extension)
  2. X25519 supported. Должен поддерживать X25519 в KeyShare
  3. HTTP/2 enabled. Для правдоподобия (большинство современных сайтов)
  4. Иностранный сайт. Не российский (чтобы IP не «пингался» внутри РФ — это будет странно). Подходят: apple.com, microsoft.com, amazon.com, cloudflare.com
  5. Существующий сайт. ALPN-handshake должен реально отдавать контент, иначе active probe получит ошибку
  6. НЕ Cloudflare. CF использует тот же IP для тысяч сайтов — если SNI не совпадёт, ответ может прийти странным
  7. Стабильный IP. Не AnyCast-CDN с динамическими IP

В 2024-2025 популярные хорошие dest'ы:

НЕ использовать

6. Полная конфигурация — сервер и клиент

Сервер (Xray-core)

{
  "log": { "loglevel": "warning" },
  "inbounds": [
    {
      "port": 443,                          // ← наружу 443, как у обычного HTTPS
      "protocol": "vless",
      "settings": {
        "clients": [
          {
            "id": "12345678-1234-1234-1234-123456789012",  // ← UUID пользователя
            "flow": "xtls-rprx-vision",                    // ← Vision overlay
            "email": "user1@vpn"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "show": false,
          "dest": "www.microsoft.com:443",                  // ← маскируемся под MS
          "xver": 0,
          "serverNames": ["www.microsoft.com"],             // ← валидные SNI
          "privateKey": "SERVER_PRIVATE_KEY_BASE64",        // ← xray x25519
          "minClientVer": "",
          "maxClientVer": "",
          "maxTimeDiff": 0,
          "shortIds": ["", "01ab", "02cd"]
        }
      }
    }
  ],
  "outbounds": [
    { "protocol": "freedom", "tag": "direct" },
    { "protocol": "blackhole", "tag": "block" }
  ],
  "routing": {
    "rules": [
      { "type": "field", "ip": ["geoip:private"], "outboundTag": "block" }
    ]
  }
}
  

Генерация ключей: xray x25519 — выведет priv/pub keys.

Клиент (Xray / sing-box / NekoBox / v2rayN)

{
  "inbounds": [
    { "port": 10808, "protocol": "socks", "listen": "127.0.0.1" }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "settings": {
        "vnext": [
          {
            "address": "VPS_IP",                            // ← IP твоего VPS
            "port": 443,
            "users": [
              {
                "id": "12345678-1234-1234-1234-123456789012",
                "flow": "xtls-rprx-vision",
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
        "realitySettings": {
          "serverName": "www.microsoft.com",              // ← маскировка под MS
          "fingerprint": "chrome",                         // ← uTLS под Chrome
          "publicKey": "SERVER_PUBLIC_KEY_BASE64",
          "shortId": "01ab",
          "spiderX": "/"                                   // ← путь спайдеринга (см. ниже)
        }
      }
    }
  ]
}
  

7. SpiderX — финальный штрих маскировки

Когда сервер Reality перехватил handshake, он отдал клиенту сертификат настоящего apple.com. После этого происходит обычный TLS application data. Но клиент НЕ открывает apple.com — он шлёт свой VPN-трафик через VLESS.

Чтобы DPI не заметил «странного поведения» (TLS-handshake с apple.com → дальше нет http-запросов к apple), Xray на стороне клиента эмулирует SpiderX: фоновые HTTP-запросы к настоящему apple.com по разным path. DPI видит: «клиент пошёл на apple.com и листает страницы» — нормально.

spiderX: "/" означает: при подключении делать GET / и эмулировать поведение браузера. Можно настраивать паттерн обхода (что и как часто запрашивать).

8. Слабости Reality

Reality не магия. Несколько ограничений:

Что может пойти не так
  1. IP сервера зачисляется в blacklist. Не по протоколу, а по объёму трафика. Если на твой IP идёт 100 ГБ/сутки — это уже подозрительно, ТСПУ может пометить «вероятно VPN». Reality не защищает от per-IP-блокировок по traffic volume.
  2. Тайминги. SpiderX делает запросы только на handshake. После — длинная сессия с маленькими/большими пакетами. Если у DPI хорошая ML-модель, она может задетектить «не настоящее браузерное поведение». Помогают uTLS + Vision + смешение реального трафика.
  3. Active probing на dest mismatch. Если активный probe из РФ подключится с SNI=apple.com к твоему IP — он получит реальный ответ apple. Но если он подключится с другим SNI к твоему IP (например, ничего не указав, или указав bing.com) — Reality его НЕ обработает (сервер ждёт правильный SNI). Это потенциальный leak. В Xray есть параметр serverNames — список допустимых SNI; всё что не в нём — отвергнуть.
  4. Reality в РФ работает в 2025 потому, что ТСПУ не научилось это всё классифицировать. К 2026-2027 ML-классификация на bidirectional flow станет проблемой даже для Reality. Решения уже разрабатываются (см. урок 14).

9. Почему Reality всё ещё работает в 2026

  1. Снаружи неотличим от настоящего HTTPS. JA3 = настоящий Chrome. SNI = настоящий популярный сайт. Сертификат = настоящий чужой. Никакой статистики, которая могла бы выделить Reality среди «настоящих HTTPS-соединений».
  2. Active probing провален. Probe видит реальный apple.com.
  3. TLS-in-TLS нет. Vision splice убирает overhead и паттерн.
  4. Не нужен домен. Тысячи клиентов могут поднять Reality на любом VPS без domain registration — нечего вносить в blacklist.
  5. Open source, активно развивается. Каждый месяц патчи.

Reality — это текущий S-тир. Других протоколов такого уровня в 2026 нет.

10. Дальше

Reality — это TCP-стрим. Есть случаи (плохой UDP-канал, мобильник в роуминге, потери), где TCP-туннель страдает. Для этого случая существуют UDP-туннели на QUIC: Hysteria 2, TUIC. Они быстрее на плохих каналах и имеют другой набор противотрюков (port hopping, BBR Brutal). Это урок 08.