【问题标题】:How to send valid HTTPS requests to a web service via SslStream and TcpClient如何通过 SslStream 和 TcpClient 向 Web 服务发送有效的 HTTPS 请求
【发布时间】:2017-05-04 20:04:39
【问题描述】:

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

这个想法当然是通过加密连接从 Google 接收基本的 HTTP 响应。这在使用未加密的 HTTP 时非常简单——我什至可以通过端口 80 telnet 到 google 并输入 GET / HTTP/1.1,然后我会收到一个不错的 HTTP 响应标头和 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() 函数超时或不提供响应?示例代码看起来非常简单,所以我很难理解我做错了什么。

【问题讨论】:

  • "" 会破坏 HTTP 请求,使其无法被 Web 服务器解析,这是什么? GET 应该以 \r\n 结束
  • 是由来自 MSDN 的参考代码中的 cmets 建议的。我会尝试用 \r\n 替换它,但我遇到了同样的行为。
  • 我知道这是一篇旧帖子,但我认为正确的终止符是 "\r\n\r\n" 而不仅仅是 \r\n。
  • @anthonyterra 你是对的 - 原因是第一个 \r\n 只会让你到达将表单数据添加到 HTTP 标头的位置。添加另一个 \r\n 信号表明表单数据已提供或不包含在内。

标签: c# asp.net sockets ssl https


【解决方案1】:

立即引起我注意的一件事是 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); 当然适用于许多网络服务;但是,在访问严格使用 TLS1.2 的站点时,我遇到了这种特定过载的问题。如果您想启用对严格 TLS1.2 代理的支持,请尝试 sslStream.AuthenticateAsClient(serverName,null,SslProtocols.Tls12,false);。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-06
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    • 2019-09-22
    • 2018-10-04
    相关资源
    最近更新 更多