Библиотека STOMP.js чаще всего работает поверх WebSocket-соединений. Без шифрования весь трафик между клиентом и брокером сообщений может быть перехвачен, модифицирован или проанализирован. Для защиты канала применяется TLS — тот же механизм, который используется в HTTPS.
В контексте WebSocket используются два варианта протокола:
| Протокол | Описание |
|---|---|
ws:// |
Нешифрованное соединение |
wss:// |
WebSocket поверх TLS |
Для production-систем использование wss:// является
обязательным требованием.
При работе STOMP.js стек соединения выглядит следующим образом:
STOMP.js
↓
WebSocket API
↓
TLS
↓
TCP
↓
Брокер сообщений
После установки TCP-соединения начинается TLS-handshake:
Базовая конфигурация защищённого подключения:
import { Client } from '@stomp/stompjs';
const client = new Client({
brokerURL: 'wss://broker.example.com/ws',
reconnectDelay: 5000,
heartbeatIncoming: 4000,
heartbeatOutgoing: 4000
});
client.activate();
Ключевой момент — использование схемы wss://.
brokerURL: 'ws://localhost:15674/ws'
Особенности:
brokerURL: 'wss://broker.example.com/ws'
Особенности:
Современные браузеры блокируют смешанный контент.
Если страница открыта через 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 обычно используется 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
Часто 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-handshake браузер выполняет:
Если сертификат недействителен, соединение не установится.
В development-среде часто используются self-signed certificates.
Проблема:
WebSocket connection failed:
ERR_CERT_AUTHORITY_INVALID
Браузер не доверяет сертификату.
Варианты решения:
Создание локального CA:
mkcert -install
Генерация сертификата:
mkcert localhost 127.0.0.1 ::1
Результат:
localhost.pem
localhost-key.pem
После этого локальный WSS начинает корректно работать в браузере.
При использовании 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 шифрование остаётся обязательным.
Часто STOMP-аутентификация строится через Bearer token.
Пример:
const client = new Client({
brokerURL: 'wss://broker.example.com/ws',
connectHeaders: {
Authorization: `Bearer ${token}`
}
});
Преимущества:
TLS создаёт дополнительную нагрузку:
Однако современные браузеры и серверы используют:
Поэтому влияние на производительность обычно минимально.
Современные production-системы должны использовать минимум TLS 1.2.
Предпочтительный вариант — TLS 1.3.
Преимущества TLS 1.3:
Сервер должен отключать слабые алгоритмы:
Плохие варианты:
Рекомендуемые:
Forward secrecy означает:
если приватный ключ сервера будет украден в будущем, старый трафик всё равно нельзя расшифровать.
Обычно используются:
При TLS-ошибках STOMP.js может выдавать ошибки активации:
client.onStompEr ror = (frame) => {
console.error(frame);
};
client.onWebSocketEr ror = (event) => {
console.error(event);
};
Однако TLS-ошибки часто появляются раньше STOMP-layer.
Поэтому диагностика выполняется через:
Сертификат просрочен.
Домен не совпадает с сертификатом.
Например:
Сертификат:
api.example.com
Подключение:
broker.example.com
Неправильная TLS-конфигурация сервера.
Часто означает:
Тестирование можно выполнить напрямую:
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.
Сервер должен запрещать:
Иначе злоумышленник может попытаться принудительно понизить уровень безопасности соединения.
HTTP Strict Transport Security заставляет браузер использовать только HTTPS/WSS.
Пример заголовка:
Strict-Transport-Security:
max-age=31536000;
includeSubDomains
Некоторые корпоративные приложения дополнительно используют certificate pinning.
Суть подхода:
клиент хранит fingerprint сертификата и проверяет его при подключении.
Это усложняет MITM-атаки даже при компрометации CA.
В production-среде сертификаты обычно обновляются автоматически.
Популярный стек:
Let's Encrypt
+
Certbot
+
Nginx
Автоматизация предотвращает:
Некоторые CDN поддерживают WSS:
Преимущества:
При reconnect STOMP.js повторно инициирует TLS-handshake.
Важно избегать:
Пример:
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:
Пример:
Set-Cookie:
SESSION=abc123;
Secure;
HttpOnly;
SameSite=Lax
Некоторые корпоративные сети выполняют TLS interception:
Browser
↓
Corporate Proxy
↓
Broker
Прокси подменяет сертификаты и расшифровывает трафик.
Это может вызывать:
Проверка TLS:
openssl s_client \
-connect broker.example.com:443
Проверка сертификатов:
openssl s_client \
-showcerts \
-connect broker.example.com:443
Безопасной практикой считается выделение отдельного endpoint:
wss://broker.example.com/stomp
Это упрощает:
Приватные ключи TLS должны регулярно обновляться.
Причины:
Типичный production-стек:
Browser
↓ HTTPS/WSS
Cloudflare
↓
Nginx
↓
RabbitMQ
Особенности:
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://