我正在尝试使用 Asio 和 OpenSSL 发送 https 网络请求。我的代码在我尝试过的大多数网站上运行良好,但在其他一些网站上,握手期间出现错误 handshake: wrong version number (SSL routines, ssl3_get_record)
.
我发现有些人遇到这个问题是因为他们在代理后面,或者因为他们试图连接到端口 80 而不是端口 443,但这里不是这种情况(据我所知),因为完全相同的代码(见下文举个例子)适用于我尝试过的大多数网站。
我试图用wireshark检查,看看我是否能发现有错误的案例和没有错误的案例之间的区别。这是我发现的:
基于这些观察,我知道我的代码能够使用 TLSv1.3,并且我认为使用 TLSv1 是问题所在。所以我试图通过
asio::ssl::context::tlsv13_client
强制 asio 对 TLS 使用 > 1 的版本。创建上下文时,或添加 asio::ssl::context::no_tlsv1
到 set_options,但 wireshark 仍然显示使用了 TLSv1 协议(protocol)。对于第二点,我对网络东西不太熟悉,所以我不确定我能得出什么结论,或者即使它与问题相关。
最小的工作示例:
#include <asio.hpp>
#include <asio/ssl.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
try
{
asio::io_context io_context;
asio::ip::tcp::resolver resolver(io_context);
asio::ip::tcp::resolver::results_type endpoints = resolver.resolve("google.com", "https"); //not working with "api.minecraftservices.com" for example
asio::ssl::context ctx(asio::ssl::context::sslv23); // also tried tlsv13_client to force v1.3, without success
ctx.set_default_verify_paths();
ctx.set_options(asio::ssl::context::default_workarounds | asio::ssl::context::verify_none);
asio::ssl::stream<asio::ip::tcp::socket> socket(io_context, ctx);
socket.set_verify_mode(asio::ssl::verify_none);
socket.set_verify_callback([](bool, asio::ssl::verify_context&) {return true; });
asio::connect(socket.lowest_layer(), endpoints);
socket.handshake(socket.client);
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
return -1;
}
return 0;
}
最佳答案
您需要更具体地了解您尝试连接的服务器:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <iostream>
namespace ssl = boost::asio::ssl;
using boost::asio::ip::tcp;
int main() {
try {
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
ssl::context ctx(ssl::context::sslv23); // also tried tlsv13_client to
// force v1.3, without success
ctx.set_default_verify_paths();
ctx.set_options(ssl::context::default_workarounds |
ssl::context::verify_none);
ssl::stream<tcp::socket> socket(io_context, ctx);
socket.set_verify_mode(ssl::verify_none);
socket.set_verify_callback([](auto&&...) { return true; });
#ifndef COLIRU
connect(socket.lowest_layer(), resolver.resolve("d7uri8nf7uskq.cloudfront.net", "https"));
#else
socket.lowest_layer().connect({boost::asio::ip::address_v4::from_string("65.9.84.220"), 443});
#endif
std::cout << "Connected to " << socket.lowest_layer().remote_endpoint() << "\n";
socket.handshake(socket.client);
} catch (std::exception const& e) {
std::cout << e.what() << std::endl;
return -1;
}
}
打印Connected to 65.9.84.220:443
更新事实上,使用 api.minecraftservices.com:443 确实可以打印
Connected to 65.9.78.95:443
handshake: wrong version number (SSL routines, ssl3_get_record) [asio.ssl:336130315]
原来你需要SNI :SSL_set_tlsext_host_name(socket.native_handle(), "api.minecraftservices.com");
然后它就可以工作了(使用不同的 IP 分辨率)Connected to 65.9.78.23:443
关于c++ - 在与 Asio 和 OpenSSL 握手期间,*某些*网站上出现错误的版本号错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71080735/