2010-12-06 34 views
5

¿Cómo puedo cerrar con gracia una sesión de Java SSL sin cerrar el socket subyacente?¿Cerrar SSL sin cerrar el socket subyacente?

El caso es que un cliente Java se conecta a un servidor (no Java), configura SSL y envía credenciales de forma segura (nombre de usuario & contraseña) al servidor. El servidor configura un entorno que se ejecuta bajo estas credenciales, genera un nuevo proceso en este entorno y le pasa el manejador de socket, pero la trampa es que este nuevo proceso no puede reutilizar la conexión SSL existente (y no puede usar la sesión SSL) reanudar) ... así que la idea es cerrar SSL antes de que se genere este nuevo proceso, y luego renegociar una sesión SSL desde cero con el nuevo proceso.

El problema es que el método de Java SSLSocket's cierra el socket además de cerrar la sesión SSL (por sending the close_notify alert). No parece haber un equivalente de la función SSL_shutdown() de OpenSSL, que permite dejar abierto el socket subyacente.

He intentado algunas cosas para evitar esto:

  1. Uso SSLSocket.startHandshake() una segunda vez, pero que automáticamente intenta reanudar la sesión SSL en caché existente (que falla, ya que el proceso de servidor generado no lo hace saber de esta sesión), y, si bien hay un método para force resuming SSL sessions or die trying, no hay ningún método para invalidar todas las sesiones en caché o deshabilitar el uso de sesiones en caché.

  2. Creando un SSLSocket sobre la parte superior de mi zócalo existente usando SSLSocketFactory.createSocket(), con autoClose en falso. Esto no impide que el método close() cierre el socket subyacente, y sospecho que el parámetro autoClose solo evita que el socket se cierre cuando falla el handshake inicial.

  3. Creación de un SSLSocket sobre un zócalo existente (como anteriormente), entonces la creación de un segundo SSLSocket utilizar para el protocolo de enlace SSL con el proceso generado (de un nuevo SSLContext). Esto falla porque cuando el servidor envía la alerta close_notify (antes de generar el subproceso), Java cierra el socket.

He oído hablar de SSLEngine, pero también he leído (aunque la fuente actualmente me escapa) que es mucho esfuerzo doloroso para escribir una aplicación correcta de SSL a través de TCP/IP a través de ella, y parece exagerado cuando todo lo que necesito es tener una versión de SSLSocket cuyo close() no llame al super.Close().

Sin embargo, SSLSocket no parece que incluso anular close() (de acuerdo con el javadoc), así que estoy seguro de cómo se engancha el método close() cuando no parece haber ningún apoyo para el registro de cierre oyentes en Socket.

La política de la empresa establece que no se pueden usar bibliotecas de cifrado de terceros, por lo que no puedo recurrir a una implementación SSL alternativa como la del Bouncy Castle para resolver el problema.

Si no podemos hacer que funcione el diseño actual de 1 socket, la alternativa es reescribir el servidor & del cliente para usar 2 sockets separados (lo cual es bastante complicado en términos de tener que contrarrestar la denegación de servicio y ataques intermedios, y ¿no se supone que SSL debería ser así en primer lugar?).

Cualquier comentario o idea sobre la forma de resolver este problema sería muy bienvenido.

+0

¿Intentó utilizar un zócalo normal en el fondo? Algo como: 'Socket s = socket nuevo (HOST, PORT); SSLSocket ssl = ...; ssl.connect (s.getRemoteSocketAddress()); ... '? (para mí al menos no cierra el socket "subyacente" ... * probablemente estoy haciendo algo mal * :)) – dacwe

+0

dacwe, tan cerca como puedo decir (ignorando la ... parte de tu fragmento), haciendo ssl.connect() creará una segunda conexión con el host y el socket 's' no se usará en absoluto para las comunicaciones SSL. – Caspar

Respuesta

2

Esto no impide que el método close() se cierre el socket subyacente

sí lo hace. De acuerdo con la documentación.

y yo sospechar que el parámetro Autoclose sólo impide la toma de de ser cerrada cuando el apretón de manos inicial falla.

No. Evita el cierre del zócalo subyacente. De acuerdo con la documentación.

Muéstranos el código.

+0

Mi error, estás en lo correcto. 'SSLSocket.close()' javadoc puede no decir nada sobre el cierre de las comunicaciones SSL y la vista de esquema de Eclipse de 'SSLSocket' no muestra un método' close' (tal vez no muestra los métodos reemplazados para las clases compiladas sin archivos adjuntos de origen)), pero de alguna manera 'SSLSocket.close()' anula la funcionalidad de 'Socket.close()'. – Caspar

+1

SSLSocket es abstracto. La clase de implementación anula close(). – EJP

+0

¡Ahh, me lo perdí, gracias! – Caspar

2

Debería poder usar un socket subyacente simple (su n. ° 3), ya que esto es lo que hacen las implementaciones de FTP con Clear Control Channel.

Tenga en cuenta que lo que está tratando de hacer lo deja abierto para un ataque man-in-the-middle entre las dos sesiones SSL a menos que tenga algún secreto entre los dos para indicar que la autenticación sigue siendo válida.

  1. ¿Utiliza la malicia de la red (¿envenenamiento ARP?) Para convertirse en un proxy entre el cliente y el servidor.
  2. Reenviar paquetes en ambas direcciones hasta que se complete la autenticación y finalice la sesión SSL. (Cualquier ALERTA SSL señalará el final, no necesitamos descifrar el contenido).
  3. Cierre el socket al cliente para que salga el error.
  4. Realizo mi propia negociación de SSL con el servidor.
  5. Proceda a operar con las credenciales del cliente.
+0

EJP respondió mi pregunta mejor, pero +1 por señalar un ataque MITM en el que no había pensado. – Caspar

Cuestiones relacionadas