¿Es posible cambiar el conector plano a SSLSocket?

Hay un servidor de socket simple que escucha en el puerto 12345 ;

 ServerSocket s = new ServerSocket(12345); 

Lo que quiero saber es que es posible que:

  1. Si el cliente envía una solicitud http , el servidor maneja la solicitud directamente,
  2. Si el cliente envía una solicitud https , ¿el servidor cambia el socket del cliente a SSLSocket?

Gracias

¿Es posible cambiar el conector plano a SSLSocket?

Sí lo es. En el lado del servidor, lo siguiente funciona:

 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, ...) convertirá de forma predeterminada el Socket existente en un SSLSocket modo SSLSocket . Como el reconocimiento de manos solo comienza cuando comienza a leer / escribir con las transmisiones de E / S, todavía es hora de cambiar el modo usando setUseClientMode(false) .

Respecto al rest de la pregunta:

Lo que quiero saber es que es posible que:

  • Si el cliente envía una solicitud http, el servidor maneja la solicitud directamente,
  • Si el cliente envía una solicitud https, ¿el servidor cambia el socket del cliente a SSLSocket?

Nuevamente, sí, es posible. A veces se denomina ” unificación de puertos ” y se implementa en Grizzly y, por lo tanto, en Glassfish .

Funciona porque tanto HTTP como TLS (sobre los que funciona HTTPS) son protocolos en los que se espera que el cliente hable primero. Por lo tanto, el servidor puede detectar si lo que el cliente envía inicialmente es un mensaje TLS ClientHello (en cuyo caso debe intentar continuar con el protocolo de enlace TLS) o una solicitud HTTP simple (por ejemplo, GET / HTTP/1.1 …).

Sospecho que la unificación de puertos es “más fácil” de usar con SSLEngine ; de lo contrario, podría ser difícil implementar una lectura anticipada en un socket simple, que aún SSLSocketFactory.createSocket(Socket, ...) convertir a través de SSLSocketFactory.createSocket(Socket, ...) .

Sin embargo, tenga en cuenta que esto todavía es bastante inusual.

No es posible servir http y https en el mismo puerto. Sin embargo, en teoría debería ser posible actualizar una conexión http existente para usar TLS si tanto el cliente como el servidor lo admiten, consulte RFC 2817 . La clase SSLSocketFactory tiene una función createSocket () que se puede usar para actualizar un socket existente a SSL / TLS.

Descargo de responsabilidad: no he intentado hacer esto, y la implementación de RFC 2817 probablemente no sea trivial.

Editar: Aparentemente estaba equivocado, como Bruno escribió, es posible servir http y https en el mismo puerto usando una tecnología llamada unificación de puertos, que usa los primeros bytes recibidos para detectar el protocolo. Hay un ejemplo de esto incluido con el marco Netty (JBoss).

La interfaz Socket / SSLSocket no permite el conveniente reconocimiento de contenido aquí: cuando comienzas a leer desde un socket y ves que solo es basura (no HTTP simple), no puedes suministrar estos datos a un nuevo SSLSocket envuelto alrededor de uno normal .

Podría usar un Socket (o SocketChannel) y mirar los datos, y luego (si no es el comienzo de una solicitud HTTP simple) pasar los mismos datos a un objeto SSLEngine para el descifrado / cifrado. Esto significa que usted debe manejar todas las llamadas de cifrado / descifrado, lo que no es totalmente trivial (al menos, es mucho más complicado que simplemente usar un SSLSocket con sus dos transmisiones, lo hice una vez).

Por supuesto, si hace esto, probablemente implemente mejor la interfaz RFC 2817, en lugar de intentar el rastreo automático de contenido.

Creo que no es en ambos aspectos, en función de lo que has publicado.

  1. Si el oyente en ServerSocket no está interpretando la solicitud como HTTP, entonces no hay magia que lo haga así.
  2. Si el oyente en ServerSocket no está descifrando la solicitud cifrada, entonces no hay magia que lo haga así.

¿Escribiste el código que está escuchando en ServerSocket ? En caso afirmativo, puede responder su propia pregunta mirando su código.

¿Alguien más escribió el código que está escuchando en ServerSocket ? Si es así, tendrás que preguntarles. ¿Le dieron alguna información sobre el protocolo esperado?