精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
我在 Ubuntu 15.04 上从 nghttp2 运行一个 HTTP2 服务器示例 (libevent-server.c)。我想使用 Wireshark 嗅探客户端-服务器之间的 HTTP2 数据包。 我没有使用任何 Web 浏览器作为客户端,因此此处解释的有关如何在 Wireshark 中读取 HTTP2 消息的提示不适用于我的项目。我使用 libcurl。 由于 HTTP2 数据包是 TLS 内部的应用层,因此 Wireshark 必须知道如何解密它;因此,我按照此处的指南向 Wireshark 提供密钥。但是,该指南警告说,“如果服务器发送 ServerKeyExchange 消息,您将无法解密数据。不幸的是,我的 Wireshark 显示服务器密钥交换是由服务器发送的。 以下是 libevent-server.c 代码的片段: SSL_load_error_strings(); SSL_library_init(); OpenSSL_add_all_algorithms(); OPENSSL_config(NULL); 我在更改为 后重新编译了代码,但仍然发送了 Server Key Exchange。OPENSSL_config(NULL)OPENSSL_no_config() 如何禁用服务器密钥交换?
正如您链接到的页面几乎正确地解释的那样,要让 Wireshark(或任何其他被动窃听者)解密 SSL/TLS 握手,必须使用普通的 RSA 密钥交换,而不是任何 Diffie-Hellman 选项(实际上是 DHE 或 ECDHE)或“临时”RSA。(“几乎”是它说“RSA 密钥已被用于加密数据”。事实上,RSA 密钥交换使用服务器 RSA 密钥来加密预主密钥,该密钥经过广泛的转换以生成用于加密和验证数据的多个密钥。 在实践中,DHE 或 ECDHE 是问题所在。这些密码套件提供所谓的完全正向保密,这意味着即使窃听者捕获并记录了您的通信,后来泄露了服务器密钥,他们也无法使用它,追溯解密记录的加密数据。尽管这些套件已经存在并且大部分得到了很长时间的支持,但在斯诺登事件之后,更多的人(浏览器和其他应用程序和中间件制造商、系统管理员、网络管理员、CISO 和审计员等)更加重视使用它们。 “临时 RSA”密钥交换仅用于 SSL/TLS 中一些早已过时的“EXPORT”密码套件。自 1995 年左右以来,人们就已经知道这些服务器是不安全的,大多数关心它们的人已经禁止使用它们很长一段时间,或者至少优先考虑完整的套件,尽管几个月前 FREAK 研究人员发现大约 5%(我认为是样本的)公共服务器仍然支持它们(这使他们的攻击能够发挥作用)。上次我选中了 OpenSSL 仍然默认启用它们,但优先级最低。 答:因此,您应该配置您的 Client 端(此处为 )或服务器(调用 )——或者如果您愿意,也可以同时配置两者 —— 以删除临时套件或直接需要 “plain” RSA 。curl--ciphersSSL_[CTX_]set_cipher_listDEFAULT:!EDH:!EECDH:!EXPORTRSA:!EXPORT:!eNULL:!SSLv2 这带来了另一个选项:如果您只需要检查基于 OpenSSL 的客户端和您控制的服务器之间的流量,就像这里一样,您可以使用 null 加密套件。这些被设计为不安全的,基本上是为了测试目的或可能非常严格的法律/外部限制,这些限制在 1990 年代被认为是可以想象的,并且不受许多实现的支持;OpenSSL 支持它们,但默认情况下禁用它们,即使您在逻辑上希望包含它们,也不会启用它们。要获得它们,您必须明确指定 (更好 ) 或非常违反直觉 .然后,您可以在 Wireshark 中读取数据,而无需解密。ALLeNULLeNULL+RSACOMPLEMENTOFALL
添加了一行 SSL_CTX_set_cipher_list(ctx, “DEFAULT:!EDH:!EECDH:!EXPORT“),则ServerKeyExchange不是由服务器发送的。我现在可以看到 HTTP2 流量。该指南暗示通配符端口 0 可用于配置 Wireshark,但这对我不起作用。我必须专门输入端口号 (443)
如果您的目标是从 Wireshark 中的 OpenSSL 应用程序读取解密的应用程序数据,请注意 RSA 私钥不是您唯一的选择,您还可以将映射传递给(预)主密钥。此功能不仅限于 SSL 客户端,尽管在使用 NSS 的那些应用程序中通常可以使用 。SSLKEYLOGFILE 有关从 OpenSSL 客户端和服务器应用程序检索预主密钥的方法,请参阅此 Sec.SE 帖子(不需要更改应用程序)。如果您想在应用程序中嵌入此类调试功能,则可以通过在握手完成时设置回调来更简洁地完成此操作。例: // converts bytes to hex void to_hex(unsigned char *dst, unsigned char *src, size_t len) { unsigned char hex[] = "0123456789abcdef"; unsigned i; for (i = 0; i < len; i++) { unsigned char c = src[i]; *dst++ = hex[c >> 4]; *dst++ = hex[c & 0xf]; } *dst = '\0'; }static FILE *ssl_keylog; void info_callback(const SSL *ssl, int where, int ret) { unsigned char rnd[SSL3_RANDOM_SIZE*2+1]; unsigned char pmk[SSL_MAX_MASTER_KEY_LENGTH*2+1]; // skip in case the session is invalid, or if it is not // a Handshake Done notification. if (!ssl || !ssl->session || !ssl->s3 || !(where & SSL_CB_HANDSHAKE_DONE)) { return; } // convert bytes to hex to_hex(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); to_hex(pmk, ssl->session->master_key, ssl->session->master_key_length); // write to SSL keylog file fprintf(keylog_file, "CLIENT_RANDOM %s %s\n", rnd, pmk); } static void run(const char *service, const char *key_file, const char *cert_file) { SSL_CTX *ssl_ctx; ... ssl_ctx = create_ssl_ctx(key_file, cert_file); if (!keylog_file) { // open key log file if any. keylog_file = fopen("premaster.txt", "a"); } // register callback (for SSL objects, use SSL_set_info_callback instead) SSL_CTX_set_info_callback(ssl_ctx, info_callback); ... }
我想使用 Wireshark 嗅探客户端-服务器之间的 HTTP2 数据包。 为此,您通常会参考 Wireshark Wiki 上的 Wireshark 和 TLS。 我的 Wireshark 显示服务器密钥交换是由服务器发送的。 我相信 Serer Key Exchange 消息总是被发送的。我认为您能做的最好的事情是禁止显示 Server Hello 中的 Server Certificate 消息。通过仅启用匿名协议来执行此操作。匿名协议放弃服务器身份验证,并允许您拦截流量。 我相信你要找的密码字符串是 “ADH:AECDH” 或 “aNULL” (通常,你明确声明 “!aNULL”)。它需要在客户端和服务器上都可用。最后,您可以在 ciphers(3) OpenSSL 手册页获取令牌列表。 大多数客户端断然拒绝匿名协议,因此可能很难真正进入该配置(并让一切正常)
ServerKeyExchange 并不总是发送的。但是,它针对所有匿名 (aNULL) 套件发送,正如您所说,这无论如何都是一个非常糟糕的主意。