Шифрование соединения

Библиотека STOMP.js чаще всего работает поверх WebSocket-соединений. Без шифрования весь трафик между клиентом и брокером сообщений может быть перехвачен, модифицирован или проанализирован. Для защиты канала применяется TLS — тот же механизм, который используется в HTTPS.

В контексте WebSocket используются два варианта протокола:

Протокол Описание
ws:// Нешифрованное соединение
wss:// WebSocket поверх TLS

Для production-систем использование wss:// является обязательным требованием.


Архитектура защищённого соединения

При работе STOMP.js стек соединения выглядит следующим образом:

STOMP.js
   ↓
WebSocket API
   ↓
TLS
   ↓
TCP
   ↓
Брокер сообщений

После установки TCP-соединения начинается TLS-handshake:

  1. Клиент инициирует подключение
  2. Сервер отправляет сертификат
  3. Клиент проверяет сертификат
  4. Генерируются ключи шифрования
  5. Создаётся защищённый канал
  6. Поверх канала запускается WebSocket
  7. Через WebSocket начинает работать STOMP

Подключение через WSS

Базовая конфигурация защищённого подключения:

import { Client } from '@stomp/stompjs';

const client = new Client({
    brokerURL: 'wss://broker.example.com/ws',

    reconnectDelay: 5000,

    heartbeatIncoming: 4000,
    heartbeatOutgoing: 4000
});

client.activate();

Ключевой момент — использование схемы wss://.


Различия между ws:// и wss://

Нешифрованный канал

brokerURL: 'ws://localhost:15674/ws'

Особенности:

  • трафик передаётся открыто
  • отсутствует защита от MITM-атак
  • данные могут быть перехвачены
  • подходит только для локальной разработки

Защищённый канал

brokerURL: 'wss://broker.example.com/ws'

Особенности:

  • весь трафик шифруется
  • сертификаты подтверждают подлинность сервера
  • поддерживается браузерная политика безопасности
  • обязателен для production

Ограничения браузеров

Современные браузеры блокируют смешанный контент.

Если страница открыта через HTTPS:

https://app.example.com

то браузер запретит подключение:

ws://broker.example.com/ws

Возникнет ошибка:

Mixed Content:
The page at 'https://app.example.com'
was loaded over HTTPS,
but attempted to connect to the insecure WebSocket endpoint.

Поэтому HTTPS-приложения обязаны использовать только wss://.


Настройка RabbitMQ для WSS

Для RabbitMQ обычно используется Web STOMP plugin.

Конфигурация:

web_stomp.ssl.port = 15673
web_stomp.ssl.cacertfile = /etc/rabbitmq/ca.crt
web_stomp.ssl.certfile = /etc/rabbitmq/server.crt
web_stomp.ssl.keyfile = /etc/rabbitmq/server.key

После настройки endpoint может выглядеть так:

wss://broker.example.com:15673/ws

Использование Nginx как TLS Proxy

Часто TLS завершается не на брокере, а на reverse proxy.

Схема:

Browser
   ↓ WSS
Nginx
   ↓ WS
RabbitMQ

Пример конфигурации Nginx:

server {
    listen 443 ssl;
    server_name broker.example.com;

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    location /ws {
        proxy_pass http://rabbitmq:15674/ws;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        proxy_set_header Host $host;
    }
}

Такой подход имеет несколько преимуществ:

  • централизованное управление сертификатами
  • упрощённое обновление TLS
  • балансировка нагрузки
  • фильтрация запросов
  • rate limiting
  • интеграция с CDN и WAF

Проверка сертификатов

Во время TLS-handshake браузер выполняет:

  • проверку цепочки сертификатов
  • проверку срока действия
  • проверку доверенного центра сертификации
  • проверку hostname

Если сертификат недействителен, соединение не установится.


Самоподписанные сертификаты

В development-среде часто используются self-signed certificates.

Проблема:

WebSocket connection failed:
ERR_CERT_AUTHORITY_INVALID

Браузер не доверяет сертификату.

Варианты решения:

  1. Добавление сертификата в trusted storage
  2. Использование локального CA
  3. mkcert
  4. development reverse proxy

Генерация локального сертификата через mkcert

Создание локального CA:

mkcert -install

Генерация сертификата:

mkcert localhost 127.0.0.1 ::1

Результат:

localhost.pem
localhost-key.pem

После этого локальный WSS начинает корректно работать в браузере.


SockJS и TLS

При использовании SockJS шифрование также определяется схемой URL.

import SockJS from 'sockjs-client';
import { Client } from '@stomp/stompjs';

const socket = new SockJS(
    'https://broker.example.com/stomp'
);

const client = new Client({
    webSocketFactory: () => socket
});

SockJS автоматически использует HTTPS/TLS.


Защита логина и пароля

STOMP поддерживает аутентификацию:

const client = new Client({
    brokerURL: 'wss://broker.example.com/ws',

    connectHeaders: {
        login: 'user',
        passcode: 'secret'
    }
});

Без TLS credentials передаются в открытом виде.

Даже при использовании JWT, API token или session token шифрование остаётся обязательным.


Использование JWT

Часто STOMP-аутентификация строится через Bearer token.

Пример:

const client = new Client({
    brokerURL: 'wss://broker.example.com/ws',

    connectHeaders: {
        Authorization: `Bearer ${token}`
    }
});

Преимущества:

  • отсутствие передачи пароля
  • централизованная авторизация
  • поддержка expiration
  • интеграция с OAuth2/OpenID Connect

TLS Handshake и производительность

TLS создаёт дополнительную нагрузку:

  • обмен сертификатами
  • асимметричное шифрование
  • генерация session keys

Однако современные браузеры и серверы используют:

  • TLS session resumption
  • session tickets
  • TLS 1.3
  • hardware acceleration

Поэтому влияние на производительность обычно минимально.


TLS 1.2 и TLS 1.3

Современные production-системы должны использовать минимум TLS 1.2.

Предпочтительный вариант — TLS 1.3.

Преимущества TLS 1.3:

  • более быстрый handshake
  • меньше round-trip
  • улучшенная криптография
  • удаление устаревших cipher suites
  • защита forward secrecy по умолчанию

Cipher Suites

Сервер должен отключать слабые алгоритмы:

Плохие варианты:

  • RC4
  • DES
  • 3DES
  • SHA1

Рекомендуемые:

  • AES-GCM
  • CHACHA20-POLY1305

Forward Secrecy

Forward secrecy означает:

если приватный ключ сервера будет украден в будущем, старый трафик всё равно нельзя расшифровать.

Обычно используются:

  • ECDHE
  • DHE

Проверка состояния соединения

При TLS-ошибках STOMP.js может выдавать ошибки активации:

client.onStompEr ror = (frame) => {
    console.error(frame);
};

client.onWebSocketEr ror = (event) => {
    console.error(event);
};

Однако TLS-ошибки часто появляются раньше STOMP-layer.

Поэтому диагностика выполняется через:

  • DevTools
  • Network tab
  • Security tab
  • browser console

Типичные ошибки TLS

CERT_DATE_INVALID

Сертификат просрочен.


ERR_CERT_COMMON_NAME_INVALID

Домен не совпадает с сертификатом.

Например:

Сертификат:
api.example.com

Подключение:
broker.example.com

ERR_SSL_PROTOCOL_ERROR

Неправильная TLS-конфигурация сервера.


WebSocket closed before connection established

Часто означает:

  • TLS handshake failure
  • блокировку reverse proxy
  • несовместимость cipher suite
  • неверную цепочку сертификатов

Проверка WSS через браузер

Тестирование можно выполнить напрямую:

const ws = new WebSocket(
    'wss://broker.example.com/ws'
);

ws.ono pen = () => {
    console.log('OPEN');
};

ws.oner ror = (e) => {
    console.error(e);
};

Если WebSocket не открывается без STOMP.js, проблема находится ниже уровня STOMP.


Защита от downgrade attack

Сервер должен запрещать:

  • SSLv2
  • SSLv3
  • TLS 1.0
  • TLS 1.1

Иначе злоумышленник может попытаться принудительно понизить уровень безопасности соединения.


HSTS

HTTP Strict Transport Security заставляет браузер использовать только HTTPS/WSS.

Пример заголовка:

Strict-Transport-Security:
max-age=31536000;
includeSubDomains

Certificate Pinning

Некоторые корпоративные приложения дополнительно используют certificate pinning.

Суть подхода:

клиент хранит fingerprint сертификата и проверяет его при подключении.

Это усложняет MITM-атаки даже при компрометации CA.


Автоматическое обновление сертификатов

В production-среде сертификаты обычно обновляются автоматически.

Популярный стек:

Let's Encrypt
+
Certbot
+
Nginx

Автоматизация предотвращает:

  • просрочку сертификатов
  • простои системы
  • ручные ошибки

WebSocket через CDN

Некоторые CDN поддерживают WSS:

  • Cloudflare
  • Fastly
  • AWS CloudFront

Преимущества:

  • глобальное TLS termination
  • защита от DDoS
  • Anycast routing
  • ускорение handshake

Безопасность reconnect-механизма

При reconnect STOMP.js повторно инициирует TLS-handshake.

Важно избегать:

  • бесконечных reconnect loops
  • reconnect storm
  • перегрузки брокера

Пример:

const client = new Client({
    brokerURL: 'wss://broker.example.com/ws',

    reconnectDelay: 5000
});

Лучше использовать exponential backoff:

let delay = 1000;

client.onWebSocketCl ose = () => {
    setTimeout(() => {
        client.activate();

        delay = Math.min(delay * 2, 30000);
    }, delay);
};

Если STOMP-аутентификация основана на cookies:

  • cookies должны иметь Secure flag
  • желательно использовать SameSite
  • необходимо применять HttpOnly

Пример:

Set-Cookie:
SESSION=abc123;
Secure;
HttpOnly;
SameSite=Lax

Корпоративные прокси и TLS interception

Некоторые корпоративные сети выполняют TLS interception:

Browser
   ↓
Corporate Proxy
   ↓
Broker

Прокси подменяет сертификаты и расшифровывает трафик.

Это может вызывать:

  • ошибки сертификатов
  • проблемы с WSS
  • нестабильные reconnect
  • блокировку WebSocket upgrade

Диагностика через OpenSSL

Проверка TLS:

openssl s_client \
-connect broker.example.com:443

Проверка сертификатов:

openssl s_client \
-showcerts \
-connect broker.example.com:443

Изоляция STOMP endpoint

Безопасной практикой считается выделение отдельного endpoint:

wss://broker.example.com/stomp

Это упрощает:

  • firewall rules
  • rate limiting
  • мониторинг
  • аудит
  • защиту API

Ротация ключей

Приватные ключи TLS должны регулярно обновляться.

Причины:

  • снижение риска компрометации
  • соответствие security policy
  • требования compliance

Безопасная production-конфигурация

Типичный production-стек:

Browser
   ↓ HTTPS/WSS
Cloudflare
   ↓
Nginx
   ↓
RabbitMQ

Особенности:

  • TLS 1.3
  • автоматическое обновление сертификатов
  • HSTS
  • WAF
  • rate limiting
  • JWT authentication
  • secure cookies
  • reverse proxy isolation

Минимальная безопасная конфигурация STOMP.js

import { Client } from '@stomp/stompjs';

const client = new Client({
    brokerURL: 'wss://broker.example.com/ws',

    reconnectDelay: 5000,

    heartbeatIncoming: 10000,
    heartbeatOutgoing: 10000,

    connectHeaders: {
        Authorization: `Bearer ${token}`
    },

    debug: (str) => {
        console.log(str);
    }
});

client.activate();

Ключевые свойства конфигурации:

  • использование wss://
  • наличие reconnect
  • heartbeat-контроль
  • токенизированная аутентификация
  • диагностика соединения