使用 Boost.Asio 和 OpenSSL 的 HTTPS 请求

2021-12-24 00:00:00 https openssl c++ boost boost-asio

我正在尝试阅读 https://mtgox.com 上的股票代码/api/0/data/ticker.php 来自我的 C++ 应用程序.我使用 Boost.Asio 和 OpenSSL,因为该服务需要 HTTPS.

I'm trying to read the ticker symbol at https://mtgox.com/api/0/data/ticker.php from my C++ application. I use Boost.Asio and OpenSSL because the service requires HTTPS.

增强版:1.47.0

OpenSSL:1.0.0d [2011 年 2 月 8 日] Win32

OpenSSL: 1.0.0d [8 Feb 2011] Win32

对于应用程序;我从 http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/ssl/client.cpp开始并修改如下:

For the application; I took the example from http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/ssl/client.cpp to get started and modified it as follows:

这是我想要连接的地方:

This is where I want to connect to:

boost::asio::ip::tcp::resolver::query query("mtgox.com", "443");

我将验证设置为无,因为否则握手会失败.我不确定这是 mtgox 的问题还是这个实现真的很严格,因为当我将证书打印到屏幕上时它看起来是合法的(并且在访问股票代码页面时 chrome 没有问题).

I set verification to none because the handshake fails otherwise. I'm not sure if this is a problem with mtgox or that this implementation is really strict because when I print the certificate to the screen it looks legit (and chrome has no problem with it when visiting the ticker page).

socket_.set_verify_mode(boost::asio::ssl::context::verify_none);

这是我发送的请求:

std::stringstream request_;

request_ << "GET /api/0/data/ticker.php HTTP/1.1
";
request_ << "Host: mtgox.com
";
request_ << "Accept-Encoding: *
";
request_ << "
";

boost::asio::async_write(socket_, boost::asio::buffer(request_.str()), boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

(完整代码:http://pastebin.com/zRTTqZVe)

我遇到了以下错误:

Connection OK!
Verifying:
/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
Sending request: 
GET /api/0/data/ticker.php HTTP 1.1
Host: mtgox.com
Accept-Encoding: *

Sending request OK!

Read failed: An existing connection was forcibly closed by the remote host

我是否朝着正确的方向前进?错误消息并没有真正描述问题,我不知道我做错了哪一步.

Am I going in the right direction with this? The error message isn't really descriptive of the problem and I don't know which step I did wrong.

更新:我使用 cURL 查看出了什么问题:

Update: I used cURL to see what went wrong:

curl --trace-ascii out.txt https://mtgox.com/api/0/data/ticker.php

(完整输出:http://pastebin.com/Rzp0RnAK)在验证过程中失败.当我连接不安全"参数时

(full output: http://pastebin.com/Rzp0RnAK) It fails during verification. When I connect with the "unsafe" parameter

curl --trace-ascii out.txt -k https://mtgox.com/api/0/data/ticker.php

(完整输出:http://pastebin.com/JR43A7ux)

一切正常.

修正:

  1. 我修正了 HTTP 标头中的拼写错误
  2. 我添加了一个根证书并且重新开启 SSL 验证.

推荐答案

简而言之:

  1. 您发送的是HTTP 1.1"而不是HTTP/1.1".这肯定足以让服务器拒绝您的请求.您的请求和 cURL 之间还有其他差异,您可能还需要更改这些参数 - 即使它们对我来说似乎有效.

  1. You send "HTTP 1.1" instead of "HTTP/1.1". That's surely enough to make the server refuse your request. There are other differences between your request and cURL's, you might need to change those params as well - even if they seem valid to me.

也许 OpenSSL 没有服务器使用的根证书,这与 Chrome 不同,这就是验证失败的原因.

Maybe OpenSSL does not have the root certificate used by the server, unlike Chrome, and that's why verification is failing.

详情:

  1. 给定一个工作和非工作工具,你应该总是比较正在发生的事情.在这里,您有 cURL 的输出和您的请求 - 比较它们显示了许多差异;通常,即使使用加密连接,您也可以使用强大的数据包嗅探器,例如 Wireshark,它会从数据包中解码尽可能多的信息.在这里它可以看到服务器实际上发送的数据包更少(我期望);另一种可能性是您的客户端没有收到服务器发送的数据(比如因为客户端有一些错误).

  1. Given a working and non-working tool, you should always compare what's happening. Here you have cURL's output and your request - comparing them showed a number of differences; usually, even with an encrypted connection, you can use a powerful packet sniffer like Wireshark, which decodes as much information from the packets as possible. Here it would allow to see that the server is actually sending less packets (I expect); another possibility would have been that your client was not getting the data sent by the server (say because the client had some bug).

如果我理解正确,curl 只显示了您需要禁用验证的原因,对吗?该证书在 chrome 上对我来说也是有效的,但根证书颁发机构是未知的;curl 提到了CA cert",即证书颁发机构的证书.根证书是可信的,因为它已经存在于客户端的证书数据库中 - 我认为 Chrome 可能拥有比 OpenSSL 更完整的数据库(cURL 和您的程序都使用它).

If I understand correctly, curl showed only why you needed to disable verification, right? The certificate looks valid for me on chrome as well, but the root certification authority is quite unknown; curl mentions the "CA cert", i.e. the certificate of the certification authority. The root certificate is trusted because it is already present in a certificate DB on the client - I think that Chrome might have a more complete DB than OpenSSL (which is used by both cURL and your program).

相关文章