Comment sécuriser des connexions de socket avec TLS/SSL (HTML)

[ Cet article est destiné aux développeurs de Windows 8.x et Windows Phone 8.x qui créent des applications Windows Runtime. Si vous développez une application pour Windows 10, voir la Documentation ]

Cette rubrique montre comment sécuriser des connexions de socket de flux avec TLS/SSL lorsque la fonctionnalité StreamSocket est utilisée dans une application du Windows Store.

Ce que vous devez savoir

Technologies

Prérequis

  • Les exemples suivants fournis dans cette rubrique sont en langage JavaScript. Des connaissances de base sur les sockets et l’utilisation de SSL/TLS sont recommandées.

Vue d’ensemble d’une connexion SSL/TLS

Le protocole SSL (Secure Sockets Layer) et le protocole TLS (Transport Layer Security) le plus récent sont des protocoles de chiffrement conçus pour fournir l’authentification et le chiffrement pour la communication réseau. Ces protocoles sont conçus pour éviter les écoutes clandestines et la falsification lors de l’envoi et la réception de données réseau. Ces protocoles utilisent un modèle client-serveur pour les échanges de protocole. Ces protocoles utilisent des certificats numériques et des autorités de certification pour vérifier que le serveur est bien celui qu’il prétend être. Le protocole TLS est documenté dans la norme RFC 5246 de l’IETF. Le protocole SSL précédent était documenté par Netscape Communications. Le terme SSL est couramment utilisé pour faire référence à ces deux protocoles.

L’objet StreamSocket peut être configuré de manière à utiliser SSL/TLS pour les communications entre le client et le serveur. Cette prise en charge de SSL/TLS est limitée à l’utilisation de l’objet StreamSocket en tant que client dans la négociation SSL/TLS. SSL/TLS ne peut actuellement pas être utilisé par StreamSocketListener avec le StreamSocket créé à la réception d’une connexion pour activer SSL/TLS sur le StreamSocket créé, dans la mesure où la négociation SSL/TLS en tant que serveur n’est pas implémentée pour un StreamSocket. La prise en charge de SSL/TLS par les clients ne comprend pas la possibilité d’utiliser des certificats clients.

Il existe deux manières de sécuriser une connexion StreamSocket avec SSL/TLS :

  • ConnectAsync - Établir la connexion initiale à un service réseau et négocier immédiatement l’utilisation de SSL/TLS pour toutes les communications.
  • UpgradeToSslAsync - Se connecter initialement à un service réseau sans chiffrement. L’application peut envoyer ou recevoir des données. Elle peut ensuite mettre à niveau la connexion afin d’utiliser les protocoles SSL/TLS pour toutes les communications à venir.

Utiliser ConnectAsync

Établit la connexion de départ avec un service réseau, puis négocie immédiatement l’utilisation de SSL/TLS pour toutes les communications. Deux méthodes ConnectAsync prennent en charge un paramètre protectionLevel :

Si le paramètre protectionLevel est défini sur Windows.Networking.Sockets.SocketProtectionLevel.Ssl lors de l’appel de l’une ou l’autre des méthodes ConnectAsync citées ci-dessus, StreamSocket doit utiliser SSL/TLS pour le chiffrement. Cette valeur doit être chiffrée et ne prend pas en charge les éléments de chiffrement NULL.

La séquence normale à utiliser avec l’une de ces méthodes ConnectAsync est la même.

  • Créez une méthode StreamSocket.
  • Si vous devez ajouter une option avancée pour le socket, utilisez la propriété StreamSocket.Control pour obtenir l’instance StreamSocketControl qui est associée à un objet StreamSocket. Définissez une propriété pour StreamSocketControl.
  • Appelez l’une des méthodes ConnectAsync ci-dessus pour démarrer une opération de connexion à une destination distante et négociez immédiatement l’utilisation de SSL/TLS.

Dans l’exemple suivant, un objet StreamSocket est créé, puis essaie d’établir une connexion au service réseau et de négocier immédiatement l’utilisation de SSL/TLS. Si la négociation réussit, toutes les communications réseau utilisant l’objet StreamSocket entre le client et le serveur réseau seront chiffrées.



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

Utiliser UpgradeToSslAsync

Établit une connexion initiale à un service réseau sans chiffrement. L’application peut envoyer ou recevoir des données, puis mettre à jour la connexion de manière à utiliser SSL/TLS pour toutes les prochaines communications. La méthode suivante est utilisée :

La méthode UpgradeToSslAsync prend deux paramètres. Le paramètre protectionLevel indique le niveau de protection souhaité. Le paramètre validationHostName est le nom d’hôte de la destination réseau distante qui est utilisée pour la validation lors de la mise à niveau vers SSL. validationHostName est en principe le même nom d’hôte que celui utilisé initialement par l’application pour établir la connexion. Si le paramètre protectionLevel a la valeur Windows.System.Socket.SocketProtectionLevel.Ssl lors de l’appel de la méthode UpgradeToSslAsync ci-dessus, l’objet StreamSocket doit utiliser SSL/TLS pour le chiffrement. Cette valeur doit être chiffrée et ne prend pas en charge les éléments de chiffrement NULL.

La séquence normale à utiliser avec la méthode UpgradeToSslAsync est la suivante :

  • Créez une méthode StreamSocket.
  • Si vous devez ajouter une option avancée pour le socket, utilisez la propriété StreamSocket.Control pour obtenir l’instance StreamSocketControl qui est associée à un objet StreamSocket. Définissez une propriété pour StreamSocketControl.
  • Si des données doivent être envoyées et reçues non chiffrées, envoyez-les maintenant.
  • Appelez la méthode UpgradeToSslAsync pour démarrer une opération de mise à niveau de la connexion vers SSL/TLS.

Dans l’exemple suivant, un objet StreamSocket est créé, essaie d’établir une connexion au service réseau, envoie des données initiales, puis négocie l’utilisation de SSL/TLS. Si la négociation réussit, toutes les communications réseau utilisant l’objet StreamSocket entre le client et le serveur réseau seront chiffrées.



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

Remarques

L’énumération SocketProtectionLevel accepte plusieurs valeurs :

  • PlainSocket - Un socket brut sans chiffrement.

  • Ssl - Un socket qui doit utiliser SSL/TLS pour le chiffrement. Cette valeur doit être chiffrée et ne prend pas en charge les éléments de chiffrement NULL.

    Cette valeur prend en charge les protocoles SSL 3.0 et TLS 1.0, ainsi que tous les éléments de chiffrement installés sur le système excepté l’élément de chiffrement NULL.

  • SslAllowNullEncryption - Un socket qui préfère utiliser SSL/TLS pour le chiffrement. Cette valeur privilégie l’utilisation du chiffrement intégral, mais autorise un chiffrement NULL (aucun chiffrement) en fonction de la configuration du serveur.

  • BluetoothEncryptionAllowNullAuthentication - Un socket Bluetooth qui privilégie l’utilisation du chiffrement, mais qui autorise l’utilisation d’un élément de chiffrement NULL (soit l’absence de chiffrement) en fonction de la configuration du serveur cible.

  • BluetoothEncryptionWithAuthentication - Un socket Bluetooth qui doit utiliser le chiffrement. Cette valeur doit être chiffrée et ne prend pas en charge les éléments de chiffrement NULL.

  • Ssl3AllowWeakEncryption - Un socket TCP qui doit utiliser SSL pour le chiffrement. Cette valeur prend en charge le protocole SSL 3.0, ainsi que tous les éléments de chiffrement installés sur le système excepté l’élément de chiffrement NULL. Elle autorise RC4 et d’autres éléments de chiffrement faibles qui sont considérés comme non sécurisés.

  • Tls10 - Un socket TCP qui doit utiliser SSL pour le chiffrement. Cette valeur prend en charge le protocole TLS 1.0, ainsi que tous les éléments de chiffrement installés sur le système excepté RC4, d’autres éléments de chiffrement faibles et l’élément de chiffrement NULL.

  • Tls11 - Un socket TCP qui doit utiliser SSL pour le chiffrement. Cette valeur prend en charge les protocoles TLS 1.1 et TLS 1.0, ainsi que tous les éléments de chiffrement installés sur le système excepté RC4, d’autres éléments de chiffrement faibles et l’élément de chiffrement NULL.

  • Tls12 - Un socket TCP qui doit utiliser SSL pour le chiffrement. Cette valeur prend en charge les protocoles TLS 1.2, TLS 1.1 et TLS 1.0, ainsi que tous les éléments de chiffrement installés sur le système excepté RC4, d’autres éléments de chiffrement faibles et l’élément de chiffrement NULL.

La valeur SslAllowNullEncryption n’est en principe pas utilisée car elle autoriserait l’utilisation d’un chiffrement NULL (soit l’absence de chiffrement) et la communication réseau risquerait alors de ne pas être chiffrée. La valeur SslAllowNullEncryption ne permet pas à la négociation SSL/TLS de valider le serveur sur la base du certificat numérique du serveur et de l’autorité de certification.

La force SSL réellement négociée à l’aide de ConnectAsync ou UpgradeToSslAsync peut être déterminée en obtenant la propriété StreamSocketinformation.ProtectionLevel.

Rubriques associées

Autre

Connexion à l’aide de sockets

Comment établir une connexion à l’aide d’un socket datagramme

Comment établir une connexion à l’aide d’un socket de flux

Comment utiliser des contrôles de socket avancés

Référence

SocketProtectionLevel

StreamSocket

StreamSocket.ConnectAsync

StreamSocket.UpgradeToSslAsync

StreamSocketinformation.ProtectionLevel

Windows.Networking.Sockets

Exemples

Exemple StreamSocket