我想写一个简单的应用程序,它抓取 HTTPS 页面的内容: https://httpbin.org/html 。
我知道如何访问其不安全 (HTTP) 版本 ( http://httpbin.org/html ),我只需要使用套接字发送请求:
std::stringstream ss;
ss << "GET /html HTTP/1.1" << "\r\n"
<< "Host: httpbin.org\r\n"
<< "Connection: close"
<< "\r\n\r\n";
std::string request = ss.str();
// socket creation, connect
send(sock, request.c_str(), request.size(), 0);
它有效。但是,当使用安全套接字( #include <openssl/ssl.h>
)时,我收到以下错误: error:14094438:SSL routines:SSL3_READ_BYTES:tlsv1 alert internal error
尝试时 result = SSL_connect(ssl);
这是代码:
#include <sys/stat.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string>
#include <iostream>
#include <sstream>
int main(int argc, char **argv)
{
int sock;
char buff[1024];
struct sockaddr_in address;
struct hostent *host = NULL;
std::string servername = "httpbin.org";
if (!inet_aton(servername.c_str(), &address.sin_addr))
if (host = gethostbyname(servername.c_str()))
address.sin_addr = *(struct in_addr*)host->h_addr;
else
return -1;
address.sin_port = htons(443);
address.sin_family = AF_INET;
std::stringstream ss;
ss << "GET /html HTTP/1.1" << "\r\n"
<< "Host: httpbin.org\r\n"
<< "Connection: close"
<< "\r\n\r\n";
std::string request = ss.str();
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) != -1)
{
if (connect(sock, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) != -1)
{
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_method());
if (!ctx)
return -1;
int result = -1;
SSL *ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
result = SSL_connect(ssl);
if (result == 0)
{
long error = ERR_get_error();
const char* error_str = ERR_error_string(error, NULL);
printf("%s\n", error_str);
return 0;
}
SSL_write(ssl, request.c_str(), request.size());
SSL_read(ssl, buff, 1024);
printf("%s\n", buff);
memset(buff, 0, 1024);
SSL_free(ssl);
SSL_CTX_free(ctx);
close(sock);
}
}
return 0;
}
原文由 Katie 发布,翻译遵循 CC BY-SA 4.0 许可协议
这意味着服务器发送回 TLSv1 警报可能是因为它不喜欢客户端在握手 (ClientHello) 中发送的信息。这可能是因为客户端只提供服务器不支持的密码,客户端使用不支持的协议版本,或者经常因为服务器需要 TLS SNI 扩展 来确定向客户端提供哪个证书。使用其他工具进行测试表明情况确实如此。因此,可以通过使用 SNI 扩展在您的代码中解决该问题: