本文轉自:http://msdn.microsoft.com/zh-cn/library/windows/apps/jj150597.aspxweb
本主題將展現在使用 StreamSocket 功能時,如何使 Windows 應用商店應用能夠保護 TLS/SSL 流套接字鏈接。windows
使用套接字和 WebSocket 啓用網絡通訊。安全
安全套接字層 (SSL) 和最新的傳輸層安全 (TLS) 都是旨在爲網絡通訊提供身份驗證和加密功能的加密協議。這些協議專門用於在發送和接收網絡數據時防止發生竊聽和篡改。 這些協議使用一種客戶端-服務器模型進行協議交換。這些協議還會使用數字證書和證書頒發機構來驗證服務器是否與其自稱的身份相符。TLS 協議記錄在 IETF RFC 5246 中。 早期的 SSL 協議由 Netscape Communications 記錄。 SSL 一般用於指這兩種協議。服務器
StreamSocket 對象能夠配置用於在客戶端和服務器之間使用 SSL/TLS 進行通訊。對 SSL/TLS 的支持僅限於在 SSL/TLS 協商中將 StreamSocket 對象用做客戶端。當系統接受一個鏈接以在被建立的 StreamSocket 上啓用 SSL/TLS 時,因爲做爲服務器的 SSL/TLS 協商沒有爲 StreamSocket 實現,因此StreamSocketListener 如今不能使用 SSL/TLS 用於被建立的 StreamSocket。 SSL/TLS 的客戶端支持不包括使用客戶端證書的功能。網絡
有如下兩種方法能夠藉助 SSL/TLS 確保 StreamSocket 鏈接的安全:app
創建與網絡服務的初始鏈接並當即協商對全部通訊使用 SSL/TLS。有兩種 ConnectAsync 方法支持傳遞protectionLevel 參數:異步
若是 protectionLevel 參數被設置爲 Windows.Networking.Sockets.SocketProtectionLevel.Ssl,當調用上述任一ConnectAsync 方法時,StreamSocket 必須使用 SSL/TLS 用於加密。此值須要加密並且毫不容許使用 NULL 密碼。socket
通常來講,使用這些 ConnectAsync 方法的順序都是相同的。async
如下示例將會建立 StreamSocket,並嘗試創建與網絡服務的鏈接並當即協商使用 SSL/TLS。若是協商成功,則在客戶端和網絡服務器之間使用 StreamSocket 的全部網絡通訊都將被加密。ide
using Windows.Networking; using Windows.Networking.Sockets; // Define some variables and set values StreamSocket clientSocket = new StreamSocket(); HostName serverHost = new HostName("www.contoso.com"); string serverServiceName = "https"; // For simplicity, the sample omits implementation of the // NotifyUser method used to display status and error messages // Try to connect to contoso using HTTPS (port 443) try { // Call ConnectAsync method with SSL await clientSocket.ConnectAsync(serverHost, serverServiceName, SocketProtectionLevel.Ssl); NotifyUser("Connected"); } catch (Exception exception) { // If this is an unknown status it means that the error is fatal and retry will likely fail. if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown) { throw; } NotifyUser("Connect failed with error: " + exception.Message); // Could retry the connection, but for this simple example // just close the socket. clientSocket.Dispose(); clientSocket = null; } // Add code to send and receive data using the clientSocket // and then close the clientSocket
先不加密創建與網絡服務的初始鏈接。應用能夠發送或接收數據。而後升級鏈接,對此後全部通訊使用 SSL/TLS。使用以下方法:
UpgradeToSslAsync 方法有兩個參數。protectionLevel 參數表示所需的保護級別。validationHostName 參數是在升級到 SSL 時用於進行驗證的遠程網絡目標的主機名。 一般狀況下,validationHostName 將是應用最初創建鏈接時所使用的相同主機名。若是 protectionLevel 參數被設置爲 Windows.System.Socket.SocketProtectionLevel.Ssl,當調用上述任一 UpgradeToSslAsync 方法時,StreamSocket 必須使用 SSL/TLS 用於加密。此值須要加密並且毫不容許使用 NULL 密碼。
通常來講,使用 UpgradeToSslAsync 方法的順序都是:
如下示例將會建立 StreamSocket,並嘗試創建與網絡服務的鏈接、發送一些初始數據,而後協商使用 SSL/TLS。若是協商成功,則在客戶端和網絡服務器之間使用 StreamSocket 的全部網絡通訊都將被加密。
using Windows.Networking; using Windows.Networking.Sockets; using Windows.Storage.Streams; // Define some variables and set values StreamSocket clientSocket = new StreamSocket(); HostName serverHost = new HostName("www.contoso.com"); string serverServiceName = "http"; // For simplicity, the sample omits implementation of the // NotifyUser method used to display status and error messages // Try to connect to contoso using HTTP (port 80) try { // Call ConnectAsync method with a plain socket await clientSocket.ConnectAsync(serverHost, serverServiceName, SocketProtectionLevel.PlainSocket); NotifyUser("Connected"); } catch (Exception exception) { // If this is an unknown status it means that the error is fatal and retry will likely fail. if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown) { throw; } NotifyUser("Connect failed with error: " + exception.Message, NotifyType.ErrorMessage); // Could retry the connection, but for this simple example // just close the socket. clientSocket.Dispose(); clientSocket = null; return; } // Now try to sent some data DataWriter writer = new DataWriter(clientSocket.OutputStream); string hello = "Hello World ☺ "; Int32 len = (int) writer.MeasureString(hello); // Gets the UTF-8 string length. writer.WriteInt32(len); writer.WriteString(hello); NotifyUser("Client: sending hello"); try { // Call StoreAsync method to store the hello message await writer.StoreAsync(); NotifyUser("Client: sent data"); writer.DetachStream(); // Detach stream, if not, DataWriter destructor will close it. } catch (Exception exception) { NotifyUser("Store failed with error: " + exception.Message); // Could retry the store, but for this simple example // just close the socket. clientSocket.Dispose(); clientSocket = null; return; } // Now upgrade the client to use SSL try { // Try to upgrade to SSL await clientSocket.UpgradeToSslAsync(SocketProtectionLevel.Ssl, serverHost); NotifyUser("Client: upgrade to SSL completed"); // Add code to send and receive data // The close clientSocket when done } catch (Exception exception) { // If this is an unknown status it means that the error is fatal and retry will likely fail. if (SocketError.GetStatus(exception.HResult) == SocketErrorStatus.Unknown) { throw; } NotifyUser("Upgrade to SSL failed with error: " + exception.Message); clientSocket.Dispose(); clientSocket = null; return; }
SocketProtectionLevel 枚舉 有三個可能的值:
一般不使用 SslAllowNullEncryption 值,由於它容許使用 NULL 密碼,這就意味着不加密,因此網絡通訊可能也不加密。SslAllowNullEncryption 值容許 SSL/TLS 協商,以根據服務器數字證書和證書頒發機構對服務器進行驗證。
若是使用 SslAllowNullEncryption 值,那麼實際上使用 ConnectAsync 或 UpgradeToSslAsync 協商獲得的 SSL 強度可經過獲取 StreamSocketinformation.ProtectionLevel 屬性來肯定。