c# - 如何通过 SslStream 和 TcpClient 向 Web 服务发送有效的 HTTPS 请求

标签 c# asp.net sockets ssl https

我实际上是在尝试设置一个 HTTPS 客户端,我可以使用它来自动测试 API 和我正在开发的其他网络服务。我熟悉使用套接字,但不太熟悉在代码中使用 SSL/TLS。我首先尝试设置一个客户端,该客户端使用以下 header 向 google.com 发送 HTTP 请求:GET/HTTP/1.1

当然,我们的想法是通过加密连接接收来自 Google 的基本 HTTP 响应。当使用未加密的 HTTP 时,这真的很容易——我什至可以通过端口 80 telnet 到 google 并输入 GET/HTTP/1.1,我会收到一个很好的 HTTP 响应 header 和 HTML 负载。实现用于发出未加密的 HTTP 请求的 C/C# 代码也不是很困难。 SSL 给我带来了困难。

使用下面的代码(在 https://msdn.microsoft.com/en-us/library/system.net.security.sslstream.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-3 找到的完整示例),它与 MSDN 提供的引用实现几乎相同,我可以成功连接到 google.com 并验证服务器证书:

        // Create a TCP/IP client socket.
        // machineName is the host running the server application.
        TcpClient client = new TcpClient(machineName, 443);
        Console.WriteLine("Client connected.");
        // Create an SSL stream that will close the client's stream.
        SslStream sslStream = new SslStream(
            client.GetStream(),
            false,
            new RemoteCertificateValidationCallback(ValidateServerCertificate),
            null
            );
        // The server name must match the name on the server certificate.
        try
        {
            sslStream.AuthenticateAsClient(serverName);
        }
        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;
        }

问题是当执行以下代码时,ReadMessage(sslStream) 指令挂起,因为我很长时间没有收到响应,而当响应最终到达时它是一个空字符串:

        // Encode a test message into a byte array.
        // Signal the end of the message using the "<EOF>".
        byte[] messsage = Encoding.UTF8.GetBytes("GET / HTTP/1.1<EOF>");
        // Send hello message to the server. 
        sslStream.Write(messsage);
        sslStream.Flush();
        // Read message from the server.
        string serverMessage = ReadMessage(sslStream);
        Console.WriteLine("Server says: {0}", serverMessage);

因此,当我通过安全套接字连接发出此请求时,我无法收到我正在寻找的 HTTP 响应(或任何东西)。从长远来看,我的想法是开始使用此客户端向我自己的 API 和 Web 服务发送定制的 HTTP 请求,但如果我什至无法从 google.com 获得通用响应,我当然无法做到这一点。有谁知道为什么 ReadMessage() 函数超时或不提供响应?示例代码看起来非常简单,所以我很难理解我做错了什么。

最佳答案

立即引起我注意的一件事是 Microsoft 示例没有为 sslStream.Write() 提供“计数”参数,我认为这可能与您的问题有关。另请注意,ReadMessage() 似乎是您尚未为其提供定义的函数。如果不知道 ReadMessage() 具体在做什么,则无法确定问题的确切原因。我修改了提供的用于发送 HTTPS 请求和读取响应的代码。它似乎适用于我迄今为止尝试过的网站。

        // Send request
        byte[] buffer = new byte[2048];
        int bytes;
        byte[] request = Encoding.UTF8.GetBytes(String.Format("GET https://{0}/  HTTP/1.1\r\nHost: {0}\r\n\r\n", serverName));
        sslStream.Write(request, 0, request.Length);
        sslStream.Flush();

        // Read response
        do
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);
            Console.Write(Encoding.UTF8.GetString(buffer, 0, bytes));
        } while (bytes == 2048);

作为旁注,我还注意到 sslStream.AuthenticateAsClient(serverName); 这当然适用于许多 Web 服务;但是,在访问严格使用 TLS1.2 的站点时,我遇到了特定重载的问题。如果您想启用对严格 TLS1.2 代理的支持,请尝试 sslStream.AuthenticateAsClient(serverName,null,SslProtocols.Tls12,false);

关于c# - 如何通过 SslStream 和 TcpClient 向 Web 服务发送有效的 HTTPS 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41228210/

相关文章:

c# - 当对象从另一个类返回时无法保存 Entity Framework 中的更改

c# - 从 URL 图像动态生成缩略图

c# - DataRow 的空引用

jquery - 如果验证失败,如何在 ASP.NET MVC 中阻止 jquery ajax 提交

java - 为什么java socket没有读取到全部数据会报错

sockets - 套接字连接可以多路复用吗?

sockets - 在两个rtpproxy服务器之间发送rtp数据包

c# - 在以不同方法创建的对象上使用

c# - 在 x64 上使用 WMI 创建 SQL Server 别名

c# - 如果场景中的多个游戏对象使用该脚本,脚本中声明的公共(public)委托(delegate)是否一定是单个实例?