Como proteger conexões seguras de soquete com TLS/SSL (HTML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente]

Este tópico mostra como proteger conexões de soquete de fluxo com TLS/SSL quando usamos o recurso StreamSocket em um aplicativo da Windows Store.

O que você precisa saber

Tecnologias

Pré-requisitos

  • Os seguintes exemplos deste tópico são fornecidos em JavaScript. Um entendimento básico de soquetes e do uso de SSL/TLS é recomendado.

Visão geral de uma conexão SSL/TLS

SSL e o mais recente TLS são protocolos criptográficos desenvolvidos para fornecer autenticação e criptografia para comunicações por rede. Esses protocolos foram desenvolvidos para impedir a interceptação e a manipulação de dados enviados ou recebidos pela rede. Esses protocolos usam um modelo cliente-servidor para as trocas de protocolos. Esses protocolos também usam certificados digitais e autoridades de certificação para verificar se o servidor é quem diz ser. O protocolo TLS está documentado na RFC 5246 da IETF. O protocolo SSL, mais antigo, foi documentado pela Netscape Communications. O SSL costuma ser usado para fazer referência a esses dois protocolos.

O objeto StreamSocket pode ser configurado para usar SSL/TLS para comunicação entre o cliente e o servidor. Esse suporte a SSL/TLS é limitado ao uso do objeto StreamSocket como o cliente na negociação SSL/TLS. Atualmente, o SSL/TLS não pode ser usado pelo StreamSocketListener com o StreamSocket criado quando uma conexão é recebida para habilitar SSL/TLS no StreamSocket criado, já que a negociação SSL/TLS como servidor não foi implementada para um StreamSocket. O suporte de cliente para SSL/TLS não inclui a capacidade de usar certificados de cliente.

Há duas maneiras de proteger uma conexão StreamSocket com SSL/TLS:

  • ConnectAsync - Estabeleça a conexão inicial com um serviço de rede e negocie imediatamente para usar SSL/TLS em todas as comunicações.
  • UpgradeToSslAsync - Conecte-se, inicialmente, a um serviço de rede sem criptografia. O aplicativo pode enviar ou receber dados. Feito isso, atualize a conexão para usar SSL/TLS em toda a comunicação adicional.

Usar ConnectAsync

Estabelece a conexão inicial com um serviço de rede e negocia imediatamente para usar SSL/TLS em todas as comunicações. Há dois métodos ConnectAsync que oferecem suporte para a passagem de um parâmetro protectionLevel:

Se o parâmetro protectionLevel estiver definido como Windows.Networking.Sockets.SocketProtectionLevel.Ssl ao chamar um dos métodos ConnectAsync acima, o StreamSocket deverá usar SSL/TLS para criptografia.. Esse valor requer criptografia e jamais permite que uma criptografia NULA seja usada.

A sequência de uso normal de um desses métodos ConnectAsync é a mesma.

  • Crie um StreamSocket.
  • Caso seja necessária uma opção avançada no soquete, use a propriedade StreamSocket.Control para obter a instância de StreamSocketControl associada a um objeto StreamSocket. Defina uma propriedade no StreamSocketControl.
  • Chame um dos métodos ConnectAsync acima para iniciar uma operação de conexão com um destino remoto e começar imediatamente a negociação do uso do SSL/TLS.

O exemplo a seguir cria um StreamSocket e tenta estabelecer uma conexão com o serviço de rede e negociar imediatamente o uso do SSL/TLS. Se a negociação for bem-sucedida, toda comunicação da rede que usar o StreamSocket entre o cliente e o servidor da rede será criptografada.



    // 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

Estabelece uma conexão inicial com um serviço de rede sem criptografia. O aplicativo pode enviar ou receber alguns dados e, então, atualizar a conexão para o uso de SSL/TLS em todas as comunicações posteriores. Isso emprega o seguinte método:

O método UpgradeToSslAsync aceita dois parâmetros. O parâmetro protectionLevel indica o nível de proteção desejado. O parâmetro validationHostName é o nome do host do destino remoto de rede usado para validação durante a atualização para SSL. Normalmente, o validationHostName seria o mesmo nome de host usado pelo aplicativo para estabelecer a conexão inicialmente. Se o parâmetro protectionLevel estiver definido como Windows.System.Socket.SocketProtectionLevel.Ssl ao chamar o método UpgradeToSslAsync acima, o StreamSocket deverá usar SSL/TLS para criptografia. Esse valor requer criptografia e jamais permite que uma criptografia NULA seja usada.

A sequência normal de uso com o método UpgradeToSslAsync é a seguinte:

  • Crie um StreamSocket.
  • Caso seja necessária uma opção avançada no soquete, use a propriedade StreamSocket.Control para obter a instância de StreamSocketControl associada a um objeto StreamSocket. Defina uma propriedade no StreamSocketControl.
  • Caso seja necessário enviar e receber dados sem criptografia, envie-os agora.
  • Chame o método UpgradeToSslAsync para iniciar uma operação de atualização da conexão para usar SSL/TLS.

O exemplo a seguir cria um StreamSocket, tenta estabelecer uma conexão com o serviço de rede, envia alguns dados iniciais e depois negocia o uso de SSL/TLS. Se a negociação for bem-sucedida, toda comunicação da rede que usar o StreamSocket entre o cliente e o servidor da rede será criptografada.



    // 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; 
    }

Comentários

A enumeração SocketProtectionLevel possui três valores possíveis:

  • PlainSocket - Um soquete simples sem criptografia.

  • Ssl - Um soquete que deve usar SSL/TLS para criptografia. Esse valor requer criptografia e jamais permite uma criptografia NULA.

    Esse valor oferece suporte aos protocolos SSL 3.0 e TLS 1.0 e a todas as criptografias instaladas no sistema, exceto a criptografia NULA.

  • SslAllowNullEncryption - Um soquete que prefere usar SSL/TLS para criptografia. Esse valor dá preferência ao uso de criptografia completa, mas permite uma criptografia NULA (sem criptografia) com base na configuração do servidor.

  • BluetoothEncryptionAllowNullAuthentication – Um soquete Bluetooth que prefere que a criptografia seja utilizada, mas permite uma criptografia NULA (sem criptografia) com base na configuração do servidor de destino.

  • BluetoothEncryptionWithAuthentication – Um soquete Bluetooth que deve usar criptografia. Esse valor requer criptografia e jamais permite uma criptografia NULA.

  • Ssl3AllowWeakEncryption – Um soquete TCP que deve usar SSL para criptografia. Esse valor oferece suporte ao protocolo SSL 3.0 e todas as criptografias instaladas no sistema, exceto a criptografia NULA. Este valor permite RC4 e outras criptografias fracas que são consideradas inseguras.

  • Tls10 – Um soquete TCP que deve usar SSL para criptografia. Esse valor oferece suporte ao protocolo TLS 1.0 e a todas as criptografias instaladas no sistema, exceto RC4, outras criptografias fracas e a criptografia NULA.

  • Tls11 – Um soquete TCP que deve usar SSL para criptografia. Esse valor oferece suporte ao protocolo TLS 1.1 e TLS 1.0 e a todas as criptografias instaladas no sistema, exceto RC4, outras criptografias fracas e a criptografia NULA.

  • Tls12 – Um soquete TCP que deve usar SSL para criptografia. Esse valor oferece suporte aos protocolos TLS 1.2, TLS 1.1 e TLS 1.0 e a todas as criptografias instaladas no sistema, exceto RC4, outras criptografias fracas e a criptografia NULA.

O valor SslAllowNullEncryption normalmente não é usado, pois permite o uso de uma criptografia NULA (que representa ausência de criptografia) e, portanto, a comunicação de rede talvez não seja criptografada. O valor SslAllowNullEncryption permite que a negociação SSL/TLS valide o servidor com base no certificado digital desse servidor e na autoridade de certificação.

O nível de segurança do SSL negociado usando ConnectAsync ou UpgradeToSslAsync poderá ser determinado com a obtenção da propriedade StreamSocketinformation.ProtectionLevel.

Tópicos relacionados

Outro

Conectando-se com soquetes

Como se conectar com um soquete de datagrama

Como se conectar com um soquete de fluxo

Como usar controles de soquete avançados

Referência

SocketProtectionLevel

StreamSocket

StreamSocket.ConnectAsync

StreamSocket.UpgradeToSslAsync

StreamSocketinformation.ProtectionLevel

Windows.Networking.Sockets

Exemplos

Exemplo do StreamSocket