Как защитить подключения через сокет с помощью протокола TLS/SSL (HTML)

[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. При разработке приложений для Windows 10 см. раздел последняя документация]

Содержание раздела Обеспечение безопасности подключений через сокет с помощью протокола TLS/SSL при использовании средства StreamSocket в приложении Магазина Windows.

Что необходимо знать

Технологии

  • Windows.Networking.Sockets

    Устанавливает сетевые подключения с использованием сокетов и протоколов WebSocket.

Необходимые условия

  • Примеры данного раздела написаны на JavaScript. Рекомендуется иметь базовое представление о сокетах и использовании протокола SSL/TLS.

Обзор SSL/TLS-подключения

SSL и его преемник TLS — это криптографические протоколы, разработанные для проверки подлинности и шифрования сетевых подключений. Они предназначены для предотвращения перехвата и незаконного изменения данных, отправляемых и получаемых по сети. Для обмена данными по этим протоколам используется модель клиент-сервер. Эти протоколы также используют цифровые сертификаты и центры сертификации для проверки подлинности сервера. Протокол TLS описан в документе RFC 5246 организации IETF. Более ранний протокол SSL документирован корпорацией Netscape Communications. Оба этих протокола часто называют просто SSL.

Объект StreamSocket можно настроить так, чтобы использовать протоколы SSL и TLS для обмена данными между клиентом и сервером. Эта поддержка протокола SSL/TLS ограничена использованием объекта StreamSocket в качестве клиента при согласовании SSL/TLS. В настоящее время объект StreamSocketListener не может использовать протоколы SSL и TLS вместе с StreamSocket, созданным при получении запроса на подключение, чтобы включить SSL и TLS для созданного StreamSocket, так как согласование SSL и TLS в качестве сервера не реализовано для StreamSocket. Поддержка клиентов для протоколов SSL и TLS не включает в себя возможность использовать сертификаты клиентов.

Есть два способа защитить подключение StreamSocket с помощью протокола SSL/TLS:

  • ConnectAsync — устанавливает начальное подключение к сетевой службе и сразу согласовывает использование протокола SSL/TLS для всех подключений.
  • UpgradeToSslAsync — сначала подключается к сетевой службе без использования шифрования. Приложение может отправлять и получать данные. Затем обновляет подключение, чтобы использовать протокол SSL/TLS для всех дальнейших подключений.

Использование ConnectAsync

Устанавливается начальное подключение к сетевой службе и сразу же согласовывается использование протокола SSL/TLS для всех подключений. Существует два метода ConnectAsync, поддерживающих передачу параметра protectionLevel:

Если параметр protectionLevel задан как Windows.Networking.Sockets.SocketProtectionLevel.Ssl при вызове любого из упомянутых выше методов ConnectAsync, то StreamSocket должен использовать протокол SSL/TLS для шифрования. Это значение требует применения шифрования и не допускает шифр NULL.

Применяется та же обычная последовательность с одним из этих методов ConnectAsync.

  • Создайте элемент управления StreamSocket.
  • Если для сокета необходим дополнительный параметр, используйте свойство StreamSocket.Control, чтобы получить экземпляр StreamSocketControl, связанный с объектом StreamSocket. Задайте свойство в StreamSocketControl.
  • Вызовите один из упомянутых выше методов ConnectAsync, чтобы начать операцию подключения к удаленному месту назначения, и сразу согласуйте использование протокола SSL/TLS.

В следующем примере создается StreamSocket, а также выполняется попытка установить подключение к сетевой службе и сразу согласовать использование протокола SSL/TLS. Если согласование выполнено успешно, все сетевые подключения между клиентом и сетевым сервером, использующие StreamSocket, будут зашифрованы.



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

Использование UpgradeToSslAsync

Устанавливается начальное подключение к сетевой службе без использования шифрования. Приложение может отправлять и получать данные. Затем подключение обновляется, чтобы использовать протокол SSL/TLS для всех дальнейших подключений. При этом используется следующий метод:

  • UpgradeToSslAsync — начинает асинхронную операцию обновления, чтобы использовать протокол SSL с объектом StreamSocket.

Метод UpgradeToSslAsync принимает два параметра. Параметр protectionLevel обозначает нужный уровень защиты. Параметр validationHostName — это имя удаленного места назначения в сети, которое используется для проверки при обновлении до протокола SSL. Как правило, validationHostName содержит то же имя узла, которое приложение использовало для начального установления подключения. Если параметр protectionLevel задан как Windows.System.Socket.SocketProtectionLevel.Ssl при вызове упомянутого выше метода UpgradeToSslAsync, то StreamSocket должен использовать протокол SSL/TLS для шифрования. Это значение требует применения шифрования и не допускает шифра NULL.

Обычная последовательность, которая должна использоваться с методом UpgradeToSslAsync, описана ниже:

  • Создайте элемент управления StreamSocket.
  • Если для сокета необходим дополнительный параметр, используйте свойство StreamSocket.Control, чтобы получить экземпляр StreamSocketControl, связанный с объектом StreamSocket. Задайте свойство в StreamSocketControl.
  • Если нужно отправить и получить какие-либо данные без шифрования, сделайте это сейчас.
  • Вызовите метод UpgradeToSslAsync, чтобы начать обновление подключения для использования протокола SSL/TLS.

В следующем примере создается StreamSocket, выполняется попытка установить подключение к сетевой службе, отправляются некоторые исходные данные, а затем согласовывается использование протокола SSL/TLS. Если согласование выполнено успешно, все сетевые подключения, использующие StreamSocket, между клиентом и сетевым сервером будут зашифрованы.



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

Замечания

Перечисление SocketProtectionLevel может иметь несколько значений:

  • PlainSocket — обычный сокет без шифрования.

  • Ssl — сокет, который должен использовать протокол SSL/TLS для шифрования. Это значение требует применения шифрования и не допускает шифра NULL.

    Это значение поддерживает протоколы SSL 3.0 и TLS 1.0 и все типы шифрования, установленные в системе, за исключением шифра NULL.

  • SslAllowNullEncryption — сокет, для которого предпочтительно использование протокола SSL/TLS для шифрования. Это означает, что предпочтение отдается полному шифрованию, но допускается шифр NULL (без шифрования) в зависимости от конфигурации сервера.

  • BluetoothEncryptionAllowNullAuthentication — сокет Bluetooth, для которого предпочтительно использовать шифрование, но допустимо использовать шифр NULL (без шифрования) в зависимости от конфигурации целевого сервера.

  • BluetoothEncryptionWithAuthentication — сокет Bluetooth, который должен использовать шифрование. Это значение требует применения шифрования и не допускает шифра NULL.

  • Ssl3AllowWeakEncryption — сокет TCP, который должен использовать протокол SSL для шифрования. Это значение поддерживает протокол SSL 3.0 и все типы шифрования, установленные в системе, за исключением шифра NULL. Это значение допускает использование RC4 и других слабых шифров, которые считаются небезопасными.

  • Tls10 — сокет TCP, который должен использовать протокол SSL для шифрования. Это значение поддерживает протокол TLS 1.0 и все типы шифрования, установленные в системе, за исключением RC4, других слабых шифров и шифра NULL.

  • Tls11 — сокет TCP, который должен использовать протокол SSL для шифрования. Это значение поддерживает протоколы TLS 1.1 и TLS 1.0 и все типы шифрования, установленные в системе, за исключением RC4, других слабых шифров и шифра NULL.

  • Tls12 — сокет TCP, который должен использовать протокол SSL для шифрования. Это значение поддерживает протоколы TLS 1.2, TLS 1.1 и TLS 1.0 и все типы шифрования, установленные в системе, за исключением RC4, других слабых шифров и шифра NULL.

Значение SslAllowNullEncryption обычно не используется, так как оно допускает шифр NULL, означающий отсутствие шифрования, следовательно, сетевое подключение может быть не зашифровано. Тем не менее значение SslAllowNullEncryption позволяет согласование SSL/TLS, чтобы проверить сервер на основе цифрового сертификата и центра сертификации.

Стойкость протокола SSL, который обычно согласовывается с помощью ConnectAsync или UpgradeToSslAsync, можно определить получением свойства StreamSocketinformation.ProtectionLevel.

Связанные разделы

Прочие ссылки

Подключение с помощью сокетов

Подключение с помощью сокета датаграмм

Подключение с помощью сокета потока

Использование расширенных элементов управления сокета

Ссылки

SocketProtectionLevel

StreamSocket

StreamSocket.ConnectAsync

StreamSocket.UpgradeToSslAsync

StreamSocketinformation.ProtectionLevel

Windows.Networking.Sockets

Примеры

Пример StreamSocket