迁移到Delphi 10.4 Sydney后,Indy SSL错误

3

在使用Delphi 10.4编译我的Win32客户端/服务器应用程序(使用INDY和TMS Sparkle)后,我遇到了SSL错误。我在服务器端使用Indy和自签名证书,在客户端也是如此。错误信息为“连接 SSL 错误。违反协议遇到 EOF。”。

我没有更改任何代码或环境,而在Delphi 10.3中它运行得很完美。我可以将问题归结为服务器端,因为旧服务器(在10.3中编译)与新客户端(在10.4中编译)一起运行,但旧客户端在尝试连接到新服务器时也会出现错误。

这是我初始化SSL的方式:

    SecureServer := TIndySparkleHTTPServer.create(nil);
    SecureServer.DefaultPort := SecurePort;
    // Initialize SSL with self signed certificate
    SSLHandler := TIdServerIOHandlerSSLOpenSSL.create(SecureServer);
    SSLHandler.SSLOptions.CertFile := SharedVals.ServerPath + 'appcert.pem';
    SSLHandler.SSLOptions.RootCertFile := SharedVals.ServerPath + 'approot.pem';
    SSLHandler.SSLOptions.KeyFile := SharedVals.ServerPath + 'appkey.pem';
    SSLHandler.SSLOptions.Method := sslvSSLv23;
    SecureServer.IOHandler := SSLHandler;

Emba在10.3中成功突破了Indy,也许这是另一个类似的案例?


1
“EOF encountered violating the protocol” 意味着服务器在 SSL/TLS 握手过程中关闭了 TCP 连接。通常情况下,如果服务器不喜欢握手中的某些内容,就会发生这种情况,但 OpenSSL 通常会在关闭连接之前向客户端发送警报。您是否检查过客户端连接后服务器是否引发了未捕获的异常?另外,您真的不应该使用 SSLOptions.Method 属性,而应改用 SSLOptions.SSLVersions 属性,例如 SSLHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSvTLSv1_2]; - Remy Lebeau
2
Embarcadero确实在10.3中破坏了Indy对OpenSSL的支持,但他们已经修复了这个问题,并且几周前为10.4获取了最新的Indy。据我所知,在最新的Indy中,TIdHTTPServer或其使用OpenSSL的功能没有任何已知问题。 - Remy Lebeau
谢谢,我调试了服务器,确实出现了“EIdHttpErrorParsindCommand”错误,其中包含“Fehler bei der Analyse einer Anweisung”,意思是“解析命令时出错”。我不知道怎么回事,打算回滚到D10.3版本... - MichaSchumann
2
TIdHTTPServer接收到格式错误的HTTP请求时,会引发EIdHTTPErrorParsingCommand异常。由于TIdHTTPServer在完成SSL/TLS握手之后才处理解密的HTTPS请求,这意味着您的服务器实际上根本没有尝试执行SSL/TLS握手,因此正在尝试将客户端的SSL/TLS握手请求解析为HTTP请求。您的SecurePort是否设置为非标准的HTTPS端口(而不是443)?如果是,请确保您的服务器具有一个OnQuerySSLPort事件处理程序,该处理程序返回该端口的VUseSSL=True - Remy Lebeau
Remy:再次感谢。我一直在使用非标准端口,通过使用一个小的辅助类将vUseSSL设置为true似乎可以解决问题。对我来说,似乎10.4在这里不会默认静默地转换为true,而10.3则会。我看到这种非默认端口行为已经在2018年的Indy中引入(Atozed更改日志)。 - MichaSchumann
显示剩余5条评论
1个回答

6

所有的功劳归功于Remy Lebau,他指引我正确的方向。但是我想通过提供在Delphi 10.4中使其重新工作的代码来回答我的问题。由于Indy中的更改发生在2018年(!),我仍然不知道为什么它在升级到10.4之前的10.3版本中完美地工作。

由于我直接在服务/守护程序项目中使用TMS Sparke Server for Indy,所以我提供了一个小类来连接OnQuerySSLPort方法,该方法期望一个对象方法。

type
  TSSLHelper = class
  // This helper class is neccessary to set ssl true
  // as it defaults to false on non standard ssl ports
    procedure QuerySSLPort(APort: Word; var VUseSSL: boolean);
  end;

...

procedure TSSLHelper.QuerySSLPort(APort: Word; var VUseSSL: boolean);
begin
  VUseSSL := true;
end;

...

SecureServer := TIndySparkleHTTPServer.create(nil);
SecureServer.DefaultPort := SecurePort;
// Initialize SSL with self signed certificate
SSLHandler := TIdServerIOHandlerSSLOpenSSL.create(SecureServer);
SSLHandler.SSLOptions.CertFile := SharedVals.ServerPath + 'appcert.pem';
SSLHandler.SSLOptions.RootCertFile := SharedVals.ServerPath + 'approot.pem';
SSLHandler.SSLOptions.KeyFile := SharedVals.ServerPath + 'appkey.pem';
SSLHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
SecureServer.IOHandler := SSLHandler;
SSLHelper := TSSLHelper.Create;
SecureServer.OnQuerySSLPort := SSLHelper.QuerySSLPort;
...

现在它的功能与以前一样。


谢谢。我刚花了5个小时来调试我的应用程序,因为它从里约移动到悉尼后停止工作了。但是通过谷歌只用了30秒就找到了解决方法。 - David Rose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接