gpt4 book ai didi

c++ - 使用 OpenSSL 内存 BIO 进行第二次 ClientHello 后验证方法未触发

转载 作者:行者123 更新时间:2023-12-03 12:47:41 24 4
gpt4 key购买 nike

我正在使用 OpenSSL 为 NodeJS 编写 native DTLS 模块。它使用内存 BIO,因此节点自己的套接字可用于控制数据流。一切似乎都正常,但我在 DOS 缓解方面遇到了一些问题。

根据规范,发送到服务器的初始 ClientHello 应被拒绝,并且服务器将发送包含要从客户端重新发回的 cookie 的 HelloVerifyRequest。这一切都工作正常,但是当客户端发回第二个 ClientHello 时,由于某种原因,DTLSv1_listen() 调用导致我的 cookie 生成方法第二次触发,而不是 cookie 验证方法。奇怪的是,如果我发回第二个 HelloVerifyRequest(与第一个 HelloVerifyRequest 的长度和内容完全相同),我最终会得到一个 ClientHello,它似乎会触发验证方法。

这是我编写的一个小测试,用于说明我正在做的事情(不完全是,跳过了一些内容,例如导入证书/ key 、调用握手后读/写的结果代码检查、释放内存等) .

TEST(New, Test) {
// Init context
auto ctx = SSL_CTX_new(DTLS_method());
SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, [](int ok, X509_STORE_CTX * context) { return 1; });
SSL_CTX_set_cookie_generate_cb(ctx, [](SSL * ssl, unsigned char * cookie, unsigned int * cookie_len) {
return 1;
});
SSL_CTX_set_cookie_verify_cb(ctx, [](SSL * ssl, const unsigned char * cookie, unsigned int cookie_len) {
return 1;
});

// Init connections
auto client = SSL_new(ctx);
auto client_rbio = BIO_new(BIO_s_mem());
auto client_wbio = BIO_new(BIO_s_mem());
SSL_set_bio(client, client_rbio, client_wbio);
SSL_set_connect_state(client);

auto server = SSL_new(ctx);
auto server_rbio = BIO_new(BIO_s_mem());
auto server_wbio = BIO_new(BIO_s_mem());
SSL_set_bio(server, server_rbio, server_wbio);
SSL_set_accept_state(server);

std::vector<unsigned char> data;

// Client Hello, no cookie
SSL_do_handshake(client);
auto data_len = BIO_ctrl_pending(client_wbio);
data.resize(data_len);
BIO_read(client_wbio, data.data(), data.size());

ASSERT_EQ(data[13], 1);

// Hello Verify Request
BIO_write(server_rbio, data.data(), data.size());
DTLSv1_listen(server, NULL);
data_len = BIO_ctrl_pending(server_wbio);
data.resize(data_len);
BIO_read(server_wbio, data.data(), data.size());

ASSERT_EQ(data[13], 3);

// Client Hello, with cookie
BIO_write(client_rbio, data.data(), data.size());
SSL_do_handshake(client);
data_len = BIO_ctrl_pending(client_wbio);
data.resize(data_len);
BIO_read(client_wbio, data.data(), data.size());

ASSERT_EQ(data[13], 1);

// Should be pass...?
BIO_write(server_rbio, data.data(), data.size());
ASSERT_EQ(DTLSv1_listen(server, NULL), 1);
}

最后一个断言失败 - 在本例中为 -1,在我的实际代码中为 0(随后的 BIO_read 获取数据[13]=3,又名 HelloVerifyRequest),但这里要注意的重要一点是,如果您附加调试器并在验证 lambda 上放置断点,它将不会被命中。

最佳答案

让我尝试揭开 CLIENT_HELLO - HELLO_VERIFY_REQUEST 的神秘面纱

RFC6347 - Denial-of-Service Countermeasures

解释说,尽管 CLIENT_HELLO 可能是欺骗性的,但 HELLO_VERIFY_REQUEST 用于证明客户端确实监听了该地址。因此,服务器使用来自 CLIENT_HELLO 的数据、客户端 IP 地址和端口以及服务器 secret 创建一个 cookie。

Cookie = HMAC(Secret, Client-IP, Client-Parameters)

服务器不会存储该 cookie,否则大规模欺骗将需要大量内存。因此,每次收到 CLIENT_HELLO 时,服务器都会重新计算 cookie。如果 CLIENT_HELLO 包含 cookie,则将其与新计算的 cookie 进行比较。如果 CLIENT_HELLO 更改了 cookie 之外的其他内容,则新计算的 cookie 现在可能会有所不同。其中包括客户端 IP(地址+端口)也必须保持不变。如果服务器根据 RFC6347 的建议更新其 secret ,则在极少数情况下 cookie 也可能会有所不同

One potential attack on this scheme is for the attacker to collect anumber of cookies from different addresses and then reuse them toattack the server. The server can defend against this attack bychanging the Secret value frequently, thus invalidating those cookies.

然后,检查您的 CLIENT_HELLO 是否已更改(可能只是源端口已更改),或者服务器是否过于频繁地更新 key 。如果您可以提供一些wireshark捕获,我可以帮助您。

关于c++ - 使用 OpenSSL 内存 BIO 进行第二次 ClientHello 后验证方法未触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53984560/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com