Можно ли изменить простой сокет на SSLSocket?
Существует простой сокет-сервер, прослушивающий порт 12345
;
ServerSocket s = new ServerSocket(12345);
Что я хочу знать, так это то, что:
- Если клиент отправит
http
запрос, сервер обрабатывает запрос напрямую, - Если клиент отправит
https
запросить, сервер поменять сокет клиента на SSLSocket?
Спасибо
4 ответа
Можно ли изменить простой сокет на SSLSocket?
Да, это. На стороне сервера работает следующее:
ServerSocketFactory ssf = ServerSocketFactory.getDefault();
ServerSocket serverSocket = ssf.createServerSocket(12345);
// I've initialised an sslContext with a keystore, as you normally would.
Socket socket = serverSocket.accept();
SSLSocketFactory sslSf = sslContext.getSocketFactory();
// The host name doesn't really matter, since we're turning it into a server socket
// (No need to match the host name to the certificate on this side).
SSLSocket sslSocket = (SSLSocket) sslSf.createSocket(socket, null,
socket.getPort(), false);
sslSocket.setUseClientMode(false);
// Use the sslSocket InputStream/OutputStream as usual.
SSLSocketFactory.createSocket(Socket, ...)
по умолчанию преобразует существующий Socket
в режим клиента SSLSocket
, Поскольку рукопожатие начинается только тогда, когда вы начинаете чтение / запись с потоками ввода / вывода, еще нужно изменить режим с помощью setUseClientMode(false)
,
Что касается остальной части вопроса:
Что я хочу знать, так это то, что:
- Если клиент отправляет запрос http, сервер обрабатывает запрос напрямую,
- Если клиент отправляет запрос https, сервер меняет сокет клиента на SSLSocket?
Опять же, да, это возможно. Иногда его называют "объединением портов", и он реализован в Grizzly и, следовательно, в Glassfish.
Это работает, потому что HTTP и TLS (по которым работает HTTPS) - это протоколы, по которым клиент должен сначала говорить. Следовательно, сервер может определить, является ли то, что клиент изначально отправляет, TLS. ClientHello
сообщение (в этом случае он должен попытаться продолжить рукопожатие TLS) или простой HTTP-запрос (например, GET / HTTP/1.1
...).
Я подозреваю, что объединение портов "проще" сделать с помощью SSLEngine
в противном случае может быть трудно реализовать упреждающее чтение на обычном сокете, которое вы все равно сможете преобразовать через SSLSocketFactory.createSocket(Socket, ...)
,
Обратите внимание, что это все еще довольно необычно, хотя.
Невозможно обслуживать оба http и https на одном и том же порту. Однако теоретически должно быть возможно обновить существующее http-соединение для использования TLS, если и клиент, и сервер поддерживают его, см. RFC 2817. Класс SSLSocketFactory имеет функцию createSocket(), которую можно использовать для обновления существующего сокета до SSL/TLS.
Отказ от ответственности: я не пытался сделать это, и внедрение RFC 2817, вероятно, нетривиально.
Изменить: Очевидно, я был неправ, как Бруно писал, что можно обслуживать http и https на одном и том же порту, используя технологию, называемую объединением портов, которая использует первые несколько байтов, полученных для обнаружения протокола. Существует пример этого, включенный в инфраструктуру Netty (JBoss).
Интерфейс Socket/SSLSocket не позволяет здесь удобное распознавание контента - когда вы начинаете читать из сокета и видите, что это всего лишь мусор (не простой HTTP), вы не можете передать эти данные новому SSLSocket, обернутому вокруг обычного.,
Вы можете использовать Socket (или SocketChannel) и просматривать данные, а затем (если это не начало простого HTTP-запроса) передавать те же данные объекту SSLEngine для дешифрования / шифрования. Это означает, что вы должны обрабатывать все вызовы шифрования / дешифрования самостоятельно, что не совсем тривиально (по крайней мере, это намного сложнее, чем просто использовать SSLSocket с двумя потоками - я делал это один раз).
Конечно, если вы сделаете это, вам, вероятно, лучше реализовать интерфейс RFC 2817, вместо того, чтобы пытаться автоматически анализировать содержимое.
Я думаю, что это не по обоим пунктам, в зависимости от того, что вы опубликовали.
- Если слушатель на
ServerSocket
не интерпретирует запрос как HTTP, то нет волшебства, которое сделает это так. - Если слушатель на
ServerSocket
не расшифровывает зашифрованный запрос, то нет волшебства, которое сделает это так.
Вы написали код, который слушает на ServerSocket
? Если да, вы можете ответить на свой вопрос, посмотрев код.
Кто-то еще написал код, который слушает на ServerSocket
? Если да, вам придется спросить их. Вам дали какую-либо информацию об ожидаемом протоколе?