SSL编程(2).NET最简单的客户端 html
在Windows平台上,实现SSL的.NET类是System.Net.Security.SslStream类。这个类既能够用于创建SSL服务,也能够用来做为SSL客户端链接远端的SSL服务。编程
最简单的SSL客户端是链接一个无需客户端验证的服务器,客户端没必要出示数字证书。对公众提供服务的门户网站的https入口通常都是如此,检验服 务器证书的有效性是客户端本身的事情。浏览器本身是一个典型的SSL客户端,因为客户端要负责验证服务器证书,因此使用可信的浏览器对于安全上网十分重 要。SSL服务器端网上很好找,随便选一个https网站做为对端,咱们的客户端演示程序就可以创建一个实际的SSL安全链接了。浏览器
这里,咱们的客户端程序链接一个拥有公网数字证书的https网站,如https: //www.alipay.com。默认的系统安全配置会检验服务器给出的证书,决定安全协商的结果。若是远端数字证书有 效,SslStream.AuthenticateAsClient函数调用会成功,不抛出任何异常。这个函数的名称不是很准确,看起来像是只作了鉴别工 做,实际上这个函数若是正常完成,意味着整个SSL握手工做的完成,包括鉴别和密钥交换。应用程序随后就能够用这个SslStream对象的读写函数与远 端服务器安全通讯,如请求一个网页等等,服务器发送帐单,用户提交用户信用卡号等敏感信息都应该在这样的安全链接中进行。安全
这里咱们先创建一个普通的TCP链接,而后在基于这个TCP链接的通讯通道,创建SSL安全链接。这里咱们不讨论普通TCP链接的创建和使用问题。服务器
咱们的例子代码的功能是,做为ssl客户端,链接一个知名的网站的https服务的端口。这个端口通常是443。ssl握手鉴别成功以后,咱们在 ssl通道上给服务器发送一个http页面请求,而后接收服务器应答的html页面数据,把页面源码直接以字符形式打印在控制台上。感兴趣的读者能够进一 步把它保存成html文件,用浏览器打开查看返回的网页。tcp
代码的简要流程以下:ide
1 创建普通tcp链接。函数
2 构造sslstream对象post
3 在try块中,调用authenticateasclient开始ssl握手过程,试图与也服务器创建ssl链接。网站
4 安全地 收发加密的数据,或者 在catch块中处理ssl握手异常。
代码全文以下:
using System;using System.Collections;using System.Net;using System.Net.Security;using System.Net.Sockets;using System.Security.Authentication;using System.Text;using System.Security.Cryptography.X509Certificates;using System.IO;namespace Examples.System.Net { public class SslTcpClient { private static Hashtable certificateErrors = new Hashtable(); // 验证服务器证书的回调函数。 public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) return true; Console.WriteLine("Certificate error: {0}", sslPolicyErrors); // 不能经过的服务器证书验证的,返回false,阻止创建链接。 return false; } public static void RunClient(string machineName, string serverName) {
// 1 创建普通tcp链接。 TcpClient client = new TcpClient(machineName, 443); Console.WriteLine("Client connected."); // 2 构造SslStream类的对象. SslStream sslStream = new SslStream( client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null ); // The server name must match the name on the server certificate. try { // 3 发起ssl握手,试图创建ssl链接.
sslStream.AuthenticateAsClient(serverName, null, SslProtocols.Tls, false); } catch (AuthenticationException e) { Console.WriteLine("Exception: {0}", e.Message); if (e.InnerException != null) { Console.WriteLine("Inner exception: {0}", e.InnerException.Message); } Console.WriteLine("Authentication failed - closing the connection."); client.Close(); return; } // Encode a test message into a byte array. // Signal the end of the message using the "<EOF>". byte[] messsage = Encoding.UTF8.GetBytes("GET " + machineName + "/ HTTP/1.0\r\n"); // 发送ssl加密数据。. sslStream.Write(messsage); sslStream.Flush(); // Read message from the server. string serverMessage = ReadMessage(sslStream); Console.WriteLine("Server says: {0}", serverMessage); // Close the client connection. client.Close(); Console.WriteLine("Client closed."); } static string ReadMessage(SslStream sslStream) { // Read the message sent by the server. // The end of the message is signaled using the // "<EOF>" marker. byte[] buffer = new byte[2048]; StringBuilder messageData = new StringBuilder(); int bytes = -1; do { //接收来自服务器的Ssl加密保护的数据。
bytes = sslStream.Read(buffer, 0, buffer.Length); // Use Decoder class to convert from bytes to UTF8 // in case a character spans two buffers. Decoder decoder = Encoding.UTF8.GetDecoder(); char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)]; decoder.GetChars(buffer, 0, bytes, chars, 0); messageData.Append(chars); } while (bytes != 0); return messageData.ToString(); } private static void DisplayUsage() { Console.WriteLine("To start the client specify:"); Console.WriteLine("clientSync machineName [serverName]"); Environment.Exit(1); } public static int Main(string[] args) { string serverCertificateName = "www.taobao.com"; string machineName = "www.taobao.com"; SslTcpClient.RunClient(machineName, serverCertificateName); return 0; } } }
在调试器中,看到的sslStream对象的状态以下:
代码运行的结果以下:
咱们看到了服务器经过SSL安全通道返回的HTML网页数据。