【问题标题】:Indy / Libssl32 access violation in SSL_accept at TIdTCPServer stopTIdTCPServer 停止时 SSL_accept 中的 Indy / Libssl32 访问冲突
【发布时间】:2018-07-04 04:22:48
【问题描述】:

我使用 Delphi 10.1 Update 2 和 Indy 10.6.2.5341。

我们在 SSL_accept 中遇到访问冲突。如果 TIdTCPServer 是使用 SSL 设置的,并且如果 TIdTCPServer 停止,则存在尚未协商 TLS 的打开连接,则会发生这种情况。

这看起来像是 Libssl32 或 Indy 中的问题。这可以通过以下代码和 Putty 使用 RAW 连接简单地复制。有谁知道防止这些崩溃的解决方案(或变通方法)?

procedure TSslCrash.HandlerOnExecute(AContext: TIdContext);
begin
  //
end;

procedure TSslCrash.HandlerOnConnect(AContext: TIdContext);
begin
  TIdSSLIOHandlerSocketBase(AContext.Connection.IOHandler).PassThrough := False;
end;

procedure TSslCrash.ButtonStartClick(Sender: TObject);
begin
  LServer := TIdTCPServer.Create;
  LIOHandler := TIdServerIOHandlerSSLOpenSSL.Create;

  LIOHandler.SSLOptions.Mode := sslmServer;
  LIOHandler.SSLOptions.Method := sslvTLSv1_2;
  LIOHandler.SSLOptions.VerifyMode := [];
  LIOHandler.SSLOptions.VerifyDepth := 0;
  LIOHandler.SSLOptions.CertFile := 'localhost.crt';
  LIOHandler.SSLOptions.RootCertFile := 'localhost.crt';
  LIOHandler.SSLOptions.KeyFile := 'localhost.key';

  LServer.Bindings.Add.Port := 10000;
  LServer.IOHandler := LIOHandler;
  LServer.OnExecute := HandlerOnExecute;
  LServer.OnConnect := HandlerOnConnect;
  LServer.Active := True;

  //Now open a RAW connection with Putty on port 10000 and keep it open
end;

procedure TSslCrash.ButtonStopClick(Sender: TObject);
begin
  if Assigned(LServer) then begin
    LServer.Active := False;  //This causes an AV in TIdSSLSocket.Accept

    FreeAndNil(LIOHandler);
    FreeAndNil(LServer);
  end;
end;

【问题讨论】:

  • 解决方法:使用执行 TLS/SSL 的反向代理(Apache HTTP 服务器),因此您可以在 Delphi 应用程序中使用纯 HTTP
  • 很遗憾,这不是我们的解决方案,因为我们无法将 Apache(或其他反向代理)与我们的解决方案一起提供。

标签: delphi ssl indy


【解决方案1】:

当 Putty 以 Raw 模式连接时,不会执行 SSL/TLS 握手,因此SSL_accept() 被卡在等待永远不会到达的握手请求。

TIdTCPServer 被停用时,它会断开活动的套接字连接,从而使其他线程中正在进行的任何阻塞套接字操作失败。在SSL_accept() 的情况下,应该取消阻止它,以便它可以退出并显示错误代码,TIdSSLSocket.Accept() 然后可以检测并包装成引发的异常(EIdOSSLUnderlyingCryptoErrorEIdOSSLAcceptErrorEIdSocketError 等,具体取决于错误代码的性质)在等待握手完成的客户端线程的上下文中。

但是,当TIdTCPServer 在停用期间断开套接字连接时,会调用TIdTCPConnection.Disconnect(),它会调用TIdIOHandler.Close()TIdSSLIOhandlerSocketOpenSSL 已被覆盖以释放其内部TIdSSLSocket 对象 - 与调用的对象相同SSL_accept()。因此,在停用线程的上下文中,底层 OpenSSL SSL 对象很可能在TIdSSLSocket.Destroy()(调用SSL_shutdown()SSL_free())中被释放,同时仍被TIdSSLObject.Accept()(调用SSL_accept()) 在客户端线程的上下文中,从而导致访问冲突。

在不改变 Indy 的源代码的情况下,没有什么可以做的。例如,可能将TIdCustomTCPServer.DoTerminateContext() 更改为调用AContext.Binding.CloseSocket() 而不是AContext.Connection.Disconnect(False),这样IOHandler 本身并没有关闭,只是底层套接字(类似于TIdCustomTCPServer.StopListening() 在终止其侦听accept() 线程时所做的事情)。

我在 Indy 的问题跟踪器中为您打开了一张票:

#218: Access Violation in SSL_accept() when deactivating TIdTCPServer

【讨论】:

  • 感谢 Remy,Indy 代码中的更改解决了这个问题。我可能发现了另一个问题(可能是错误,在禁用 TIdTCPServer 时破坏 TIdContext 时 Indy SSL 代码中的 AV)。如果我有清晰简单的复制,我会回复你。
猜你喜欢
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2019-04-16
  • 2017-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多