Condividi tramite


Come proteggere le connessioni socket con TLS/SSL (HTML)

[ Questo articolo è rivolto agli sviluppatori per Windows 8.x e Windows Phone 8.x che realizzano app di Windows Runtime. Gli sviluppatori che usano Windows 10 possono vedere Documentazione aggiornata ]

Questo argomento mostra come proteggere le connessioni socket di flusso con TLS/SSL quando usi la funzionalità StreamSocket per un'app di Windows Store.

Cosa sapere

Tecnologie

Prerequisiti

  • Gli esempi contenuti in questo argomento sono scritti in JavaScript. È necessaria una conoscenza di base dei socket e dell'uso di SSL/TLS.

Panoramica di una connessione SSL/TLS

SSL (Secure Sockets Layer) e il più recente TLS (Transport Layer Security) sono protocolli di crittografia progettati per fornire servizi di autenticazione e crittografia per le comunicazioni di rete. Questi protocolli impediscono l'intercettazione e la manomissione durante l'invio e la ricezione di dati di rete. Per gli scambi dei protocolli viene usato un modello client-server. Questi protocolli usano inoltre certificati digitali e autorità di certificazione per verificare l'identità del server. Il protocollo TLS è documentato nella RFC 5246 di IETF. Il precedente protocollo SSL era stato documentato da Netscape Communications. Il termine SSL viene spesso usato per fare riferimento a entrambi questi protocolli.

Puoi configurare l'oggetto StreamSocket in modo da usare SSL/TLS per le comunicazioni tra il client e il server. Il supporto di SSL/TLS è disponibile solo quando l'oggetto StreamSocket viene usato come client nella negoziazione SSL/TLS. SSL/TLS attualmente non può essere usato da StreamSocketListener con l'oggetto StreamSocket creato durante la ricezione di una connessione per abilitare SSL/TLS nell'oggetto StreamSocket, perché la negoziazione SSL/TLS come server non è implementata per StreamSocket. Il supporto client di SSL/TLS non include la capacità di utilizzare i certificati client.

Per proteggere una connessione StreamSocket usando SSL/TLS, puoi scegliere tra due modalità:

  • ConnectAsync - Puoi impostare la connessione iniziale a un servizio di rete e negoziare immediatamente l'uso di SSL/TLS per tutte le comunicazioni.
  • UpgradeToSslAsync - Puoi stabilire inizialmente la connessione a un servizio di rete senza crittografia. Dopo che l'app ha inviato o ricevuto alcuni dati, puoi aggiornare la connessione in modo da usare SSL/TLS per tutte le future comunicazioni.

Usare ConnectAsync

Stabilisce la connessione iniziale a un servizio di rete e quindi negozia immediatamente l'uso di SSL/TLS per tutte le comunicazioni. Esistono due metodi ConnectAsync che supportano il passaggio di un parametro protectionLevel:

Se il parametro protectionLevel è impostato su Windows.Networking.Sockets.SocketProtectionLevel.Ssl durante la chiamata di uno dei metodi ConnectAsync indicati sopra, StreamSocket deve usare SSL/TLS per la crittografia. Questo valore richiede la crittografia e non consente di usare NULL.

La sequenza da seguire è la stessa per entrambi i metodi ConnectAsync.

  • Crea un oggetto StreamSocket.
  • Se è necessaria un'opzione avanzata nel socket, usa la proprietà StreamSocket.Control per ottenere l'istanza StreamSocketControl associata a un oggetto StreamSocket. Imposta una proprietà per StreamSocketControl.
  • Chiama uno dei metodi ConnectAsync indicati sopra per avviare un'operazione in modo da stabilire una connessione a una destinazione remota e negoziare immediatamente l'uso di SSL/TLS.

L'esempio seguente crea un oggetto StreamSocket e quindi tenta di stabilire una connessione al servizio di rete e di negoziare immediatamente l'uso di SSL/TLS. Se la negoziazione ha esito positivo, tutte le comunicazioni di rete che usano StreamSocket tra il client e il server di rete verranno crittografate.



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

Usare UpgradeToSslAsync

Stabilisce una connessione iniziale a un servizio di rete senza crittografia. Dopo che l'app ha inviato o ricevuto alcuni dati, aggiorna la connessione in modo da usare SSL/TLS per tutte le future comunicazioni. A tale scopo viene usato il metodo seguente:

Il metodo UpgradeToSslAsync accetta due parametri. Il parametro protectionLevel indica il livello di protezione desiderato. Il parametro validationHostName indica il nome host della destinazione di rete remota usato per la convalida durante l'aggiornamento a SSL. In genere, il parametro validationHostName contiene il nome host usato dall'app per stabilire inizialmente la connessione. Se il parametro protectionLevel è impostato su Windows.System.Socket.SocketProtectionLevel.Ssl durante la chiamata del metodo UpgradeToSslAsync indicato sopra, StreamSocket deve usare SSL/TLS per la crittografia. Questo valore richiede la crittografia e non consente di usare NULL.

La sequenza da seguire con il metodo UpgradeToSslAsync è la seguente:

  • Crea un oggetto StreamSocket.
  • Se è necessaria un'opzione avanzata nel socket, usa la proprietà StreamSocket.Control per ottenere l'istanza StreamSocketControl associata a un oggetto StreamSocket. Imposta una proprietà per StreamSocketControl.
  • Se è necessario inviare e ricevere dati in forma non crittografata, inviali ora.
  • Chiama il metodo UpgradeToSslAsync per avviare un'operazione di aggiornamento della connessione in modo da usare SSL/TLS.

L'esempio seguente crea un oggetto StreamSocket, tenta di stabilire una connessione al servizio di rete, invia alcuni dati iniziali e quindi negozia l'uso di SSL/TLS. Se la negoziazione ha esito positivo, tutte le comunicazioni di rete che usano StreamSocket tra il client e il server di rete verranno crittografate.



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

Osservazioni

L'enumerazione SocketProtectionLevel accetta diversi valori possibili:

  • PlainSocket - Un socket normale senza crittografia.

  • Ssl - Un socket che deve usare SSL/TLS per la crittografia. Questo valore richiede la crittografia e non consente di usare NULL.

    Questo valore supporta i protocolli SSL 3.0 e TLS 1.0 e tutta la crittografia installata sul sistema ad eccezione di NULL.

  • SslAllowNullEncryption - Un socket che usa preferibilmente SSL/TLS per la crittografia. Questo valore prevede la crittografia completa come impostazione preferenziale, ma consente di usare NULL (nessuna crittografia) se necessario in base alla configurazione del server.

  • BluetoothEncryptionAllowNullAuthentication - Un socket Bluetooth che preferisce che venga usata la crittografia, ma ammette un NULL (nessuna crittografia) in base alla configurazione del server di destinazione.

  • BluetoothEncryptionWithAuthentication - Un socket Bluetooth che deve usare la crittografia. Questo valore richiede la crittografia e non consente di usare NULL.

  • Ssl3AllowWeakEncryption - Un socket TCP che deve usare SSL per la crittografia. Questo valore supporta il protocollo SSL 3.0 e tutta la crittografia installata sul sistema ad eccezione di NULL. Questo valore ammette RC4 e altra crittografia debole considerata non sicura.

  • Tls10 - Un socket TCP che deve usare SSL per la crittografia. Questo valore supporta il protocollo TLS 3.0 e tutta la crittografia installata sul sistema ad eccezione di RC4, altra crittografia debole e NULL.

  • Tls11 - Un socket TCP che deve usare SSL per la crittografia. Questo valore supporta i protocolli TLS 1.1 e TLS 1.0 e tutta la crittografia installata sul sistema ad eccezione di RC4, altra crittografia debole e NULL.

  • Tls12 - Un socket TCP che deve usare SSL per la crittografia. Questo valore supporta i protocolli TLS 1.2, TLS 1.1 e TLS 1.0 e tutta la crittografia installata sul sistema ad eccezione di RC4, altra crittografia debole e NULL.

Il valore SslAllowNullEncryption in genere non viene usato, perché consente l'uso della crittografia NULL e, di conseguenza, comunicazioni di rete non crittografate. Il valore SslAllowNullEncryption consente la negoziazione SSL/TLS per la convalida del server in base al relativo certificato digitale e all'autorità di certificazione.

Puoi determinare il livello SSL negoziato mediante ConnectAsync o UpgradeToSslAsync recuperando la proprietà StreamSocketinformation.ProtectionLevel.

Argomenti correlati

Other

Connessione con i socket

Come connettersi con un socket di datagramma

Come connettersi con un socket di flusso

Come usare i controlli avanzati dei socket

Riferimento

SocketProtectionLevel

StreamSocket

StreamSocket.ConnectAsync

StreamSocket.UpgradeToSslAsync

StreamSocketinformation.ProtectionLevel

Windows.Networking.Sockets

Esempi

Esempio StreamSocket