当前位置: 首页 > 知识库问答 >
问题:

MTLS和http客户端连接池使用情况

丁曦哲
2023-03-14

出身背景

  • 我需要连接到不同客户端的服务器。
  • 每个客户端连接应该使用唯一的TLS证书。
  • 服务器上的MTLS已就位。
  • 我想使用连池来提高延迟。

使用以下超文本传输协议客户端

<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.12</version>
</dependency>

我的假设当管理连接池中的连接时,当选择连接时,在选择连接池中的相同连接之前应该考虑客户端证书。我不希望连接为clientA使用clientB TLS证书,反之亦然。

问题是这个假设是真的吗?

情景1)

我将每条路线的最大连接数设置为2。我为客户端a(池中的一个连接)调用MTLS安全服务器。我为客户端a(池中的两个连接)调用MTLS安全服务器。这是否应该重用第一个连接?

情景2)

我有最大连接每路由设置为2.我打电话给客户端A的MTLS安全服务器(池中的一个连接)我打电话给客户端B的MTLS安全服务器(池中的两个连接)

然而,第二次调用似乎没有进行完全握手,而是使用clientA证书。

我希望第二次通话需要一次完整的握手,而且无论如何连接都不相关。

这是预期的行为吗?我是不是漏掉了什么明显的东西?

更新的简单测试用例

我们现在使用的是http上下文,所以我附加了更新的日志。我也简化了测试用例,现在它连接到同一个服务器两次,每次都应该使用不同的客户端证书。

该应用程序使用SpringBoot,具有一个restTemplate和一个httpClient。

它使用私有密钥策略来决定在与服务器通信时使用什么私有密钥/证书。

第一个连接使用密钥别名“e2e\u transport\u key\u id\u franek”(您将在日志中看到这一点)

第二个连接应使用别名“e2e_transport_key_id_pdw”(在日志中从未见过)

我们正在建立的第二个连接应使用别名为“e2e_transport_key_id_pdw”的密钥/证书,但会话已恢复请参见第448行尝试恢复会话。这意味着我们不能使用PrivateKeys策略来选择要使用的客户端证书。

如何强制客户端连接不重用我们打算使用不同客户端证书的连接的会话?

客户端日志https://pastebin.com/zN0EW3Qy

共有2个答案

洪梓
2023-03-14

这个假设是真的吗?

你的假设是正确的。HttpClient 4和5能够跟踪与HTTP连接相关的用户特定状态(NTLM上下文、TLS用户标识等),并在重新使用持久连接时将其考虑在内。

情景1)

后者调用应该重用现有连接,只要它与前者共享相同的执行上下文。

情景2)

不,它不是。请提供展示问题的会话的完整上下文/电线日志,我会尽力找出原因。

http://hc.apache.org/httpcomponents-client-4.5.x/logging.html

柳志专
2023-03-14

这个假设是真的吗?

你的假设是对的。连接池中用于请求和释放连接的方法都使用一个名为state的附加参数。此状态参数通常采用用户令牌,如果未进行身份验证,则为null

只有使用用于将连接释放回连接池的相同用户令牌请求连接时,才能重新使用连接。

此机制也适用于SSL客户端证书。成功的SSL握手后,将释放SSL连接以及代表用户令牌的X500主体。此令牌还存储在用于请求的HttpContext对象中。要在后续HTTP请求中重新使用已释放的连接,还必须重新使用第一个HTTP请求的HttpContext

情景1

clientA.execute(new HttpGet("..."));
clientA.execute(new HttpGet("..."));

第一个请求触发完整的SSL握手。使用用户令牌释放连接。第二个请求使用一个新的HttpContext,它不包含任何用户令牌。因此,池中的连接不能重复使用,并且使用完全握手创建新连接。

情景2

HttpContext context = new HttpClientContext();
clientA.execute(new HttpGet("..."), context);
clientB.execute(new HttpGet("..."), context);

如前所述,用户令牌存储在HttpContext中。因此,如果您从第一个请求重新使用HttpContext,则第二个请求可以重新使用已经存在的连接,即使您使用具有不同连接工厂/客户端证书的不同客户端。如果该连接正在使用中,将使用clientB的连接工厂创建一个新连接。

要分离clientAclientB并确保每个客户端只重复使用连接,您必须为每个客户端使用一个HttpContext,并为每个请求重复使用上下文:

HttpContext contextA = new HttpClientContext();
clientA.execute(new HttpGet("..."), contextA);
clientA.execute(new HttpGet("..."), contextA);

HttpContext contextB = new HttpClientContext();
clientB.execute(new HttpGet("..."), contextB);

请注意,在会话超时或请求重新协商的情况下,即使重新使用连接,也可能需要完全握手。

 类似资料:
  • 我试图理解netty http客户端连接池。如果是NIO和异步的,那么这个连接池的意义是什么? 例如:如果服务A调用服务B,并且服务A的客户端连接池计数设置为50,那么这是否意味着我们最多只能发出50个并行请求? 更新: 我在3.5秒内完成了所有通话。理想情况下,有一个连接,我应该在150秒内完成。

  • 执行kafka客户端的生产者/消费者连接池有意义吗? kafka是否在内部维护已初始化并准备好使用的连接对象列表? 我们希望最小化连接创建的时间,这样在发送/接收消息时就不会有额外的开销。 目前,我们正在使用apache共享池库来保持连接。 任何帮助都将不胜感激。

  • 问题内容: 我正在设计一个将Redis用作数据库的Web服务,并且我想了解使用Redis与StackService客户端连接的最佳实践。 关键是我一直在阅读有关Redis的文章,发现与服务器交互的最佳方法是使用单个并发连接。 问题是,尽管每当Web客户端向Web服务发出请求时,我都会使用 PooledRedisClientManager ,但我又获得了一个到Redis服务器的连接客户端(打开的连接

  • 我对Google Cloud Bigtable做了一个负载测试,制作了一个虚拟的web应用程序,用于处理向Bigtable写入数据和从Bigtable读取数据的请求。一开始,我只使用一个Bigtable连接作为单例,并跨所有线程(请求)重用它。当我增加请求数量时,我注意到性能正在变慢。不知何故,我没有增加节点的数量,而是想到了创建多个Bigtable连接,然后将它们随机分配给任何线程,从而提高了性

  • 下面的代码使用的是ApacheHTTP客户端4.5版本的池连接管理器。如果我发出50个请求,我会在netstat中看到50个不同的tcp端口被使用,但在任何时候都最多使用5个连接。我在wire shark中也看到了filter

  • 问题内容: 如何使用HttpClient创建连接池? 我必须经常连接同一台服务器。值得建立这样一个游泳池吗? 是否可以保持实时连接并将其用于各种请求,如果可以,我该如何做? 我正在使用Apache HTTP Client在Java中进行开发。 问题答案: [假设Java和Apache的HttpClient] 使用ThreadSafeClientConnManager。将单个全局实例传递给每个Htt