Compartir a través de


Cómo asegurar conexiones de sockets con TLS/SSL (HTML)

[ Este artículo está destinado a desarrolladores de Windows 8.x y Windows Phone 8.x que escriben aplicaciones de Windows en tiempo de ejecución. Si estás desarrollando para Windows 10, consulta la documentación más reciente

En este tema se muestra cómo proteger conexiones de sockets de secuencias con TLS/SSL cuando se usa la característica StreamSocket en una aplicación de la Tienda Windows.

Lo que debes saber

Tecnologías

Requisitos previos

  • Los siguientes ejemplos de este tema se proporcionan en JavaScript. Se recomienda tener un conocimiento básico sobre sockets y el uso de SSL/TLS.

Introducción a una conexión de SSL/TLS

Los protocolos Capa de sockets seguros (SSL) y Seguridad de la capa de transporte (TLS) son protocolos criptográficos diseñados para proporcionar autenticación y cifrado para comunicaciones de red. Estos protocolos están diseñados para evitar interceptaciones y alteraciones cuando se envían y reciben datos de red. Usan un modelo de cliente-servidor para los intercambios de protocolos. También usan certificados digitales y entidades de certificación para comprobar que el servidor sea el que dice ser. El protocolo TLS está documentado en IETF RFC 5246. El protocolo SSL anterior estaba documentado por Netscape Communications. SSL se usa normalmente para hacer referencia a ambos protocolos.

El objeto StreamSocket se puede configurar para usar SSL/TLS en comunicaciones entre el cliente y el servidor. Esta compatibilidad con SSL/TLS se limita al uso del objeto StreamSocket como el cliente en la negociación de SSL/TLS. Actualmente StreamSocketListener con el StreamSocket creado, no puede usar SSL/TLS cuando se recibe una conexión para habilitarlo en el StreamSocket creado, porque la negociación de SSL/TLS como servidor no se implementa para un StreamSocket. La compatibilidad del cliente con SSL/TLS no incluye la capacidad de usar certificados de cliente.

Hay dos formas de asegurar una conexión de StreamSocket con SSL/TLS:

  • ConnectAsync - Establece la conexión inicial a un servicio de red y negocia inmediatamente el uso de SSL/TLS para todas las comunicaciones.
  • UpgradeToSslAsync - Conecta inicialmente a un servicio de red sin cifrado. La aplicación puede enviar o recibir datos. A continuación, actualiza la conexión para usar SSL/TLS en todas las comunicaciones.

Usar ConnectAsync

Establece la conexión inicial a un servicio de red y negocia inmediatamente el uso de SSL/TLS para todas las comunicaciones. Hay dos métodos ConnectAsync que admiten pasar un parámetro protectionLevel:

Si el parámetro protectionLevel se establece en Windows.Networking.Sockets.SocketProtectionLevel.Ssl cuando se llama a cualesquiera de los dos métodos ConnectAsync mencionados arriba, el StreamSocket debe usar SSL/TLS para el cifrado. Este valor requiere el cifrado y nunca permite el uso de un cifrado NULL.

La secuencia normal para usar con uno de estos métodos ConnectAsync es la misma.

  • Crear un StreamSocket.
  • Si se necesita una opción avanzada en el socket, usa la propiedad StreamSocket.Control para obtener la instancia StreamSocketControl asociada con un objeto StreamSocket. Establece una propiedad en el StreamSocketControl.
  • Llama a uno de los métodos ConnectAsync mencionados arriba para iniciar una operación de conexión con un destino remoto y negocia inmediatamente el uso de SSL/TLS.

El siguiente ejemplo crea un StreamSocket e intenta establecer una conexión al servicio de red y negociar de inmediato el uso de SSL/TLS. Si la negociación se realizó correctamente, toda comunicación de red que use el StreamSocket entre el cliente y el servidor de red, será cifrada.



    // Define some global variables that can be used from
    // multiple functions as needed 
    var clientSocket = null;
    var serverHostName = null;
    var serverServiceName = null;


    function openClient() {
        clientSocket = new Windows.Networking.Sockets.StreamSocket();
        // Try to connect to contoso using HTTPS (port 443)
        serverHostName = new Windows.Networking.HostName("www.contoso.com");
        serverServiceName = "https";

        // Call connectAsync method with SSL
        clientSocket.connectAsync(serverHostName, serverServiceName, Sockets.SocketProtectionLevel.Ssl).done(onClientAccept, onConnectError);
    }

    // For simplicity, the sample omits implementation of the
    // displayStatus method used to display status and error messages 

    // If the client connection was accepted, display
    // a message to the user
    function onClientAccept() {
        socketSample.displayStatus("Client: connection completed.");
    }

    // The connection failed so display an error message
    // Could retry the connection, but for this simple example
    // just close the socket.
    function onConnectError(reason) {
       socketsSample.displayStatus(reason);
       clientSocket.close();
       clientSocket = null; 
    }

Usar UpgradeToSslAsync

Establece una conexión inicial a un servicio de red sin cifrado. La aplicación puede enviar o recibir algunos datos. A continuación, actualiza la conexión para usar SSL/TLS en todas las comunicaciones. Esto usa el siguiente método:

El método UpgradeToSslAsync toma dos parámetros. El parámetro protectionLevel indica el nivel de protección deseado. El parámetro validationHostName es el nombre de host del destino de red remota que se usa para la validación, cuando se actualiza a SSL. Por lo general, el validationHostName es el mismo nombre de host que usó la aplicación para establecer inicialmente la conexión. Si el parámetro protectionLevel se establece en Windows.System.Socket.SocketProtectionLevel.Ssl cuando se llama al método UpgradeToSslAsync mencionado arriba, el StreamSocket debe usar SSL/TLS para el cifrado. Este valor requiere el cifrado y nunca permite el uso de un cifrado NULL.

La secuencia normal para usar con el método UpgradeToSslAsync es la siguiente:

  • Crear un StreamSocket.
  • Si se necesita una opción avanzada en el socket, usa la propiedad StreamSocket.Control para obtener la instancia StreamSocketControl asociada con un objeto StreamSocket. Establece una propiedad en el StreamSocketControl.
  • Si algún dato necesita enviarse y recibirse sin cifrar, envíalo ahora.
  • Llama al método UpgradeToSslAsync para iniciar una operación de actualización para usar SSL/TLS en la conexión.

El siguiente ejemplo crea un StreamSocket, intenta establecer una conexión al servicio de red, envía algunos datos iniciales y después negocia para usar SSL/TLS. Si la negociación se realiza correctamente, toda comunicación de red que use el StreamSocket entre el cliente y el servidor de red, será cifrada.



    // Define some global variables that can be used from
    // multiple functions as needed
    var clientSocket = null;
    var serverHostName = null;
    var serverServiceName = null;

    function openClient() {
        clientSocket = new Windows.Networking.Sockets.StreamSocket();
        // Try to connect to contoso initially using HTTP
        serverHostName = new Windows.Networking.HostName("www.contoso.com");
        serverServiceName = "http";

        // Call ConnectAsync method to establish initial connection
        clientSocket.connectAsync(serverHostName, serverServiceName).done(onClientAccept, onConnectError);
    }

    // For simplicity, the sample omits implementation of the
    // displayStatus method used to display status and error messages 

    // If the client connection was accepted, display
    // a message to the user
    function onClientAccept() {
        socketSample.displayStatus("Client: connection completed.");
        sendHello();
    }

    // The connection failed so display an error message
    // We could retry the connection, but for this simple example
    // we just close the socket.
    function onConnectError(reason) {
        socketsSample.displayStatus(reason);
        clientSocket.close();
        clientSocket = null; 
    }

    // Send some data in a simple format that is
    // the length of the string of data in a 4-byte integer
    // followed by the string
    function sendHello() {
        if (!clientSocket) {
            socketsSample.displayStatus("Client: you must connect the client before using it.");
            return;
        }
        var writer = new Windows.Storage.Streams.DataWriter(socketsSample.clientSocket.outputStream);
        var string = "Hello World ☺ ";
        var len = writer.measureString(string); // Gets the UTF-8 string length.
        writer.writeInt32(len);
        writer.writeString(string);
        socketsSample.displayStatus("Client: sending hello.");
        writer.storeAsync().done(onStore, onSendError);
        writer.detachStream(); // Detach stream, if not, DataWriter destructor will close it.
    }

    function onStore() {
        socketsSample.displayStatus("Client: sent hello.");
        upgradeClient();
    }

    function onSendError(reason) {
        socketsSample.displayStatus(reason);
        clientSocket.close();
        clientSocket = null; 
    }

    function upgradeClient() {
        if (!clientSocket) {
            socketsSample.displayStatus("Client: you must connect the client before using it.");
            return;
        }
        var validationName = serverHostName;
        upgradeToSslAsync(SocketProtectionLevel.Ssl, serverHostName).done(onUpgradeAccept, onUpgradeError);
    }         

    // If upgrade to SSL was successful, display message to user
    function onUpgradeAccept() {
        socketSample.displayStatus("Client: upgrade to SSL completed.");
    }

    // The upgrade connection failed so display an error message
    // We could retry the upgrade possibly changing the validationHostname, 
    // but for this simple example we just close the socket.
    function onUpgradeError(reason) {
        socketsSample.displayStatus(reason);
        clientSocket.close();
        clientSocket = null; 
    }

Observaciones

La enumeración SocketProtectionLevel puede tener varios valores:

  • PlainSocket: un socket convencional sin cifrado.

  • Ssl - Un socket que debe usar SSL/TLS para el cifrado. Este valor requiere el cifrado y nunca permite un cifrado NULL.

    Este valor es compatible con los protocolos SSL 3.0 y TLS 1.0 y todos los cifrados instalados en el sistema salvo el cifrado NULL.

  • SslAllowNullEncryption: un socket que prefiere usar SSL/TLS para el cifrado. Este valor prefiere el uso del cifrado completo, pero permite un cifrado NULL (sin cifrado) en función de la configuración del servidor.

  • BluetoothEncryptionAllowNullAuthentication - Un socket Bluetooth que prefiere que se utilice ese cifrado, pero permite un cifrado NULL (sin cifrado) basado en la configuración del servidor de destino.

  • BluetoothEncryptionWithAuthentication - Un socket Bluetooth que debe usar cifrado. Este valor requiere el cifrado y nunca permite un cifrado NULL.

  • Ssl3AllowWeakEncryption - Un socket TCP que debe usar SSL para el cifrado. Este valor es compatible con el protocolo SSL 3.0 y todos los cifrados instalados en el sistema salvo el cifrado NULL. Este valor permite el cifrado RC4 y otros cifrados débiles que no son considerados seguros.

  • Tls10 - Un socket TCP que debe usar SSL para el cifrado. Este valor es compatible con el protocolo TLS 1.0 y todos los cifrados instalados en el sistema salvo el cifrado RC4, otros cifrados débiles y el cifrado NULL.

  • Tls11 - Un socket TCP que debe usar SSL para el cifrado. Este valor es compatible con los protocolos TLS 1.1 y TLS 1.0 y con todos los cifrados instalados en el sistema salvo el cifrado RC4, otros cifrados débiles y el cifrado NULL.

  • Tls12 - Un socket TCP que debe usar SSL para el cifrado. Este valor es compatible con los protocolos TLS 1.2, TLS 1.1 y TLS 1.0 y con todos los cifrados instalados en el sistema salvo el cifrado RC4, otros cifrados débiles y el cifrado NULL.

El valor SslAllowNullEncryption no se usa normalmente porque podría permitir un cifrado NULL, por lo cual la comunicación de red podría no ser cifrada. El valor SslAllowNullEncryption permite que la negociación SSL/TLS valide el servidor en función del certificado digital y autoridad de certificación que tenga.

La intensidad de SSL realmente negociada con ConnectAsync o UpgradeToSslAsync puede determinarse al obtener la propiedad StreamSocketinformation.ProtectionLevel.

Temas relacionados

Otros

Conexión con sockets

Cómo conectar con un socket de datagramas

Cómo conectar con un socket de secuencias

Cómo usar controles de sockets avanzados

Referencia

SocketProtectionLevel

StreamSocket

StreamSocket.ConnectAsync

StreamSocket.UpgradeToSslAsync

StreamSocketinformation.ProtectionLevel

Windows.Networking.Sockets

Muestras

Muestra de StreamSocket