Включение sensitive-информации в сообщения WebSocket
![]() |
Критичность: СРЕДНИЙ |
Описание
Данная уязвимость весьма схожа с классической уязвимостью передачи чувствительной информации по протоколу HTTP/HTTPS. Особенностью является лишь протокол передачи данных, а именно WebSocket. Как и в случае с HTTP необходимо дополнительно удостовериться, что канал передачи данных защищен шифрованием (схема передачи данных начинается с wss://
). При достаточной защите канала с использованием корректно реализованного SSL-Pinning передача конфиденциальной информации в сообщениях WebSocket не является уязвимостью. Однако, как показывает практика, для данного типа обмена информацией очень часто забывают реализовывать защиту от перехвата данных, что позволяет осуществить атаку MiTM (Man in the Middle — человек посередине).
Потенциальные риски включения чувствительной информации в сообщения WebSocket:
-
Атака «человек посередине». Злоумышленник может расположиться между клиентом и сервером и перехватывать трафик WebSocket, модифицируя или подделывая сообщения для кражи или манипуляции чувствительной информацией.
-
Похищение сессии. Если в сообщения WebSocket включены токены или учетные данные, злоумышленник может похитить сеанс и выдавать себя за пользователя, получая несанкционированный доступ к приложению или чувствительным данным.
-
Утечка данных. Если чувствительная информация случайно записывается или хранится в небезопасном виде на стороне клиента или сервера, она может оказаться доступной для злоумышленников.
Рекомендации
Основной рекомендацией в данном случае является использование SSL-Pinning. Суть этого метода в том, что на этапе SSL-Handshake (см. рис. 1) после второго шага, когда сервер присылает нам свой сертификат с открытым ключом, приложение проверяет, что определенные параметры этого сертификата совпадают с тем, что оно ожидает получить (то есть некоторые данные, которые «зашиты» в приложении и которые мы ожидаем получить от своего сервера).
Важно отметить, что конкретная реализация закрепления SSL в коммуникации через WebSocket может варьироваться в зависимости от используемого языка программирования, фреймворка или библиотеки. Библиотеки WebSocket часто предоставляют API или функции для реализации пользовательской логики проверки SSL-сертификата.
Кроме того, закрепление SSL само по себе может быть недостаточным для всесторонней защиты коммуникации через WebSocket. Рекомендуется комбинировать SSL-Pinning с другими мерами безопасности, такими как шифрование особо важных передаваемых данных.
Пример подключения проверки сертификата для WebSocket.
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class SecureWebSocketManager {
private final String SERVER_URL = "wss://example.com/websocket";
private final String CERTIFICATE_FILENAME = "server_certificate.crt";
private final OkHttpClient client;
private WebSocket webSocket;
public SecureWebSocketManager() {
// Initialize OkHttpClient with SSL pinning
client = createPinnedOkHttpClient();
}
public void connect() {
Request request = new Request.Builder().url(SERVER_URL).build();
webSocket = client.newWebSocket(request, webSocketListener);
}
public void disconnect() {
if (webSocket != null) {
webSocket.cancel();
webSocket = null;
}
}
private OkHttpClient createPinnedOkHttpClient() {
try {
// Load server certificate from assets
InputStream certificateInputStream = context.getAssets().open(CERTIFICATE_FILENAME);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(certificateInputStream);
certificateInputStream.close();
// Create TrustManager with pinned certificate
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("pinned_certificate", certificate);
trustManagerFactory.init(keyStore);
// Create SSLContext with pinned TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
// Create OkHttpClient with pinned SSLContext
return new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagerFactory.getTrustManagers()[0]).build();
} catch (Exception e) {
e.printStackTrace();
}
return new OkHttpClient();
}
private final WebSocketListener webSocketListener = new WebSocketListener() {
// Implement WebSocket listener methods here
// onOpen, onMessage, onClosing, onFailure, etc.
};
}
В этом примере класс SecureWebSocketManager
инкапсулирует логику подключения WebSocket с использованием SSL-Pinning. Замените wss://example.com/websocket
на фактический URL WebSocket, а server_certificate.crt
— на имя файла вашего серверного сертификата (разместите файл сертификата в папке assets).
Также не забывайте правильно обрабатывать исключения и включить обработку ошибок SSL.