我想发送此消息" Hello world! \ n再见世界!" 使用以下代码。此代码在2个SSL记录中发送消息,但我需要将其发送到1个SSL记录中。
我读过有关base64 here和here的内容,但我不知道如何在我的代码中使用它们!任何人都可以帮我解决我的问题。
问题:我想在一个部分发送消息,而不是用" \ n"分隔的2部分发送消息!
更多说明:我使用OpenSSL s_client连接它,我强迫它使用TLSv1并使用wireshark嗅探网络。实际上,此代码简化为更大的数据库代理项目。在主项目中,我们需要向不受我们控制的服务器发送消息,并且它只能处理1个SSL记录。
我的OpenSSL命令:
s_client -connect 127.0.0.1:9999 -tls1
消息的Wireshark结果:
17 03 01 00 24 db f3 59 37 98 78 3b b6 06 b0 c1 66 0c 78 04 4d 50 60 54 19 37 fe
77 65 27 7f 4e e8 4e 9a d7 94 66 3f 0d 03 17 03 01 00 34 83 a8 39 b3 3e 9a 35 7b
a2 64 07 35 9b c5 d7 d0 c9 03 3c 43 ac d8 1c ad d5 0f 55 34 10 6c 99 3e 57 b1 51
d4 a5 36 6a 8e 23 08 e0 2d 33 c1 53 63 4e d2 bd bd
我的模拟代码:
#include <cstdlib>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <unistd.h>
using namespace std;
static void ssl_set_sys_error(int ssl_error)
{
int error = 0;
switch (ssl_error) {
case SSL_ERROR_ZERO_RETURN:
error = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
#ifdef SSL_ERROR_WANT_CONNECT
case SSL_ERROR_WANT_CONNECT:
#endif
#ifdef SSL_ERROR_WANT_ACCEPT
case SSL_ERROR_WANT_ACCEPT:
#endif
error = 1;
break;
case SSL_ERROR_SSL:
/* Protocol error. */
#ifdef EPROTO
error = EPROTO;
#else
error = SOCKET_ECONNRESET;
#endif
break;
case SSL_ERROR_SYSCALL:
case SSL_ERROR_NONE:
default:
break;
};
}
int main()
{
/*
------------------ START Initialize Server ------------------
*/
int serverfd, clientfd;
struct sockaddr_in vir_serv_addr, cli_addr;
serverfd = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *) &vir_serv_addr, sizeof (vir_serv_addr));
vir_serv_addr.sin_family = AF_INET;
vir_serv_addr.sin_addr.s_addr = INADDR_ANY;
vir_serv_addr.sin_port = htons(9999);
bind(serverfd, (struct sockaddr *) &vir_serv_addr, sizeof (vir_serv_addr));
listen(serverfd, 5);
socklen_t client = sizeof (cli_addr);
clientfd = accept(serverfd, (struct sockaddr*) &cli_addr, (socklen_t*) & client);
/*
------------------- END Initialize Server -------------------
*/
/*
------------------ START SSL ------------------
*/
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX* context = SSL_CTX_new(TLS_server_method());
SSL_CTX_set_ecdh_auto(context, 1);
SSL_CTX_use_certificate_file(context, "server-cert.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(context, "server-key.pem", SSL_FILETYPE_PEM);
SSL_CTX_load_verify_locations(context, "ca-cert.pem", NULL);
SSL_CTX_check_private_key(context);
SSL* ssl = SSL_new(context);
BIO *rbio = BIO_new(BIO_s_mem());
BIO *wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
char* buffer[8192];
int n;
SSL_set_accept_state(ssl);
while (!SSL_is_init_finished(ssl)) {
n = recv(clientfd, buffer, 8192, 0);
n = BIO_write(rbio, buffer, n);
int r = SSL_do_handshake(ssl);
n = BIO_read(wbio, buffer, 8192);
n = send(clientfd, buffer, n, 0);
bzero(buffer, 8192);
BIO_flush(rbio);
BIO_flush(wbio);
if (r != 1) {
ERR_print_errors_fp(stderr);
int err_SSL_get_error = SSL_get_error(ssl, r);
switch (err_SSL_get_error) {
case SSL_ERROR_NONE:
case SSL_ERROR_SSL:
return 0;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
continue;
default:
return 0;
}
}
}
string message = "Hello world! \n Bye world!";
n = SSL_write(ssl, message.c_str(), message.size());
n = BIO_read(wbio, buffer, 8192);
n = send(clientfd, buffer, n, 0);
/*
------------------- END SSL -------------------
*/
}
答案 0 :(得分:4)
确实非常有趣的问题。这里发生的是单个SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
导致两个应用程序数据SSL帧(类型0x17)。这种情况只发生在TLS 1.0上,即没有TLS 1.1或TLS 1.2。
虽然它可能看起来像一个错误但实际上是为了对抗BEAST和使用SSL 3.0和TLS 1.0中与CBC密码相关的协议漏洞的类似攻击。通过插入导致第一个SSL帧的空数据片段来实现这种保护,该SSL帧实际上不包含实际数据。类似的这种0 / n分裂的保护以1 / n-1分裂的形式存在于其他TLS堆栈中。
由于此攻击不会影响TLS 1.1和TLS 1.2,因此不会启用保护。有关此保护措施的详细信息,请参阅Why does Firefox split HTTPS request?和Is BEAST really fixed in all modern browsers?。
但是,由于您承担了一些无法处理此行为的错误应用程序,因此您需要找到一种方法来禁用它。这可以通过选择一个不是CBC的密码(但TLS 1.0中没有好的密码)或者只是禁用保护来完成:
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
您可以使用SSL_OP_ALL
而不是 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
,其中包括针对错误TLS实施的所有解决方法,包括此方法。