Delphi的TNetHTTPRequest/TNetHTTPClient在Win 10上可以工作,但在Win 7上不能。

5
在源代码下方添加了新的详细信息。
在 Delphi 中存在一个问题,即网络代码在 Win 10 上运行正常,但在 Win 7 上却不行。我正在尝试连接到 haveibeenpwned.com(HIBP)的小项目中。Win 7 返回“Error getting Server Certificate”。
为了解决 Win 7 的问题,我在 TNetHTTPRequest 和 TNetHTTPClient 中都添加了 OnValidateServerCertificate。在 Win 10 和 Win 7 上,OnValidateServerCertificate 看起来都没有被调用。
我在 2 台 Win 10 计算机和 2 台 Win 7 计算机上进行了测试,结果相同。 1)为什么 Win 7 返回“Error getting Server Certificate”? 2)为什么在 Win 10 或 Win 7 上不会调用 OnValidateServerCertificate?
感谢任何帮助!
unit MainUnt;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Net.URLClient, 
System.Net.HttpClientComponent,
  System.Net.HttpClient;

type
  TForm9 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    function HIBPGetRangeResults( const AFirst5CharHashStr: String;
                                  out ARangeResultsStr: String;
                                  out AErrStr: String ): Boolean; inline;
    procedure OnValidateServerCertificate( const Sender: TObject;
                                       const ARequest: TURLRequest;
                                       const Certificate: TCertificate;
                                       var Accepted: Boolean );
  end;

var
  Form9: TForm9;

implementation

{$R *.dfm}

//SHA1( Pa$$word ): 775440A2B268C2F58A9A61B10CC10125703B3015
procedure TForm9.Button1Click(Sender: TObject);
var
  TmpErrStr: String;
  TmpResultsStr: String;
begin
  //HIBP Range wants only the first 5 charactsers so search is anonymous.
  if HIBPGetRangeResults( '77544', TmpResultsStr, TmpErrStr ) then
    ShowMessage( TmpResultsStr )
  else
    ShowMessage( TmpErrStr );
end;

function TForm9.HIBPGetRangeResults( const AFirst5CharHashStr: String;
                                     out ARangeResultsStr, AErrStr: String): 
Boolean;
const
  //GET https://api.pwnedpasswords.com/range/{first 5 hash chars}
  //I don't know of another site at this point that works on Win 10, but 
fails on Win 7.
  kServiceNameStr = 'https://api.pwnedpasswords.com/range/';
var
  TmpNetHTTPRequest: TNetHTTPRequest;
  TmpNetHTTPClient: TNetHTTPClient;
  TmpIHTTPResponse: IHTTPResponse;
begin
  Result := False;
  try
    TmpNetHTTPRequest := TNetHTTPRequest.Create( Nil );
    TmpNetHTTPClient := TNetHTTPClient.Create( Nil );
    try
      TmpNetHTTPClient.OnValidateServerCertificate := 
OnValidateServerCertificate;
      TmpNetHTTPClient.ConnectionTimeout := 3000;
      TmpNetHTTPClient.ResponseTimeout := 3000;
      TmpNetHTTPClient.UserAgent := 'Testing'; //HIBP wants User Agent 
filled.

      TmpNetHTTPRequest.OnValidateServerCertificate := 
OnValidateServerCertificate;
      TmpNetHTTPRequest.ConnectionTimeout := 3000;
      TmpNetHTTPRequest.Client := TmpNetHTTPClient;
      TmpNetHTTPRequest.URL := kServiceNameStr + AFirst5CharHashStr;

      TmpIHTTPResponse := TmpNetHTTPRequest.Execute;
      if TmpIHTTPResponse.StatusCode=200 then
      begin
        ARangeResultsStr := TmpIHTTPResponse.ContentAsString;
        Result := True;
      end
      else
      begin
        AErrStr := 'Result:' + TmpIHTTPResponse.StatusText;
      end;
    finally
      FreeAndNil( TmpNetHTTPClient );
      FreeAndNil( TmpNetHTTPRequest );
    end;
  except on E: Exception do
    AErrStr := E.Message;
  end;
end;

procedure TForm9.OnValidateServerCertificate( const Sender: TObject;
                                              const ARequest: TURLRequest;
                                              const Certificate: 
TCertificate;
                                              var Accepted: Boolean );
begin
  //Just to know it's been called at all.
  //Not called in Win 10 or Win 7.
  Beep;
end;

end.

链接https://api.pwnedpasswords.com/range/55555(哈希值的前5个字符样本)在IE中返回了证书错误。我在Win 7 Internet选项的高级设置中添加了TLS 1.1和1.2。这使得浏览器可以正常工作。
但是,程序仍然无法正常工作。因此,我搜索了Delphi源代码(Berlin)中的“获取服务器证书错误”,找到了“SNetHttpGetServerCertificate”。它位于System.Net.HttpClient中。
procedure THTTPClient.DoValidateServerCertificate(LRequest: THTTPRequest);

...

LServerCertificate := DoGetSSLCertificateFromServer(LRequest);
if LServerCertificate.Expiry = 0 then
  raise 
ENetHTTPCertificateException.CreateRes(@SNetHttpGetServerCertificate);

这似乎是唯一会引发异常的地方。不幸的是,在那里设置断点(即使启用了Debug DCUs)也没有触发。

在TWinHTTPClient.DoExecuteRequest中存在ServerCertificateInvalid的可能性,我正在跟踪此问题。我无法确定我的Win 10机器是否在Win 7上触发了该问题。

另外,我调用的域似乎使用了非常现代化的SSL配置:https://www.ssllabs.com/ssltest/analyze.html?d=api.pwnedpasswords.com&s=104.17.70.67

也许某些内容与此配置、Delphi(Berlin)和Win 7不兼容?

感谢任何帮助!

3个回答

7
实际上找到了解决方案,与Delphi无关。来自微软的解释如下:
应用程序和服务使用WinHTTP进行安全套接字层(SSL)连接时,使用WINHTTP_OPTION_SECURE_PROTOCOLS标志的应用程序和服务无法使用TLS 1.1或TLS 1.2协议。这是因为该标志的定义不包括这些应用程序和服务。
此更新添加了DefaultSecureProtocols注册表项的支持,允许系统管理员指定在使用WINHTTP_OPTION_SECURE_PROTOCOLS标志时应使用哪些SSL协议。
这可以使某些旨在使用WinHTTP默认标志构建的应用程序能够本地利用更新的TLS 1.2或TLS 1.1协议,而无需对应用程序进行任何更新。
修复方法:

https://support.microsoft.com/en-au/help/3140245/


2
我去添加更新目录中的更新,结果发现它已经安装了。从https://support.microsoft.com/en-au/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in下载并安装Easy Fix解决了问题。不幸的是,让我的用户都安装Easy Fix并不可行。所以实际上,我选择了转移到Amazon S3来避免这个问题。然而,2borG为其他服务找到了一个很好的解决方案,所以我点赞并将其设为首选答案。 - DelphiGuy
如果需要部署此项任务,可以从上面的链接中获取所需的注册表条目。当我说“Easy Fix”不可行时,我没有考虑到这一点。 - DelphiGuy

0

我也遇到了同样的问题,访问https://www.geocaching.com/account/login时出现了“服务器证书无效或不存在”的错误提示。

在Windows 10上工作没有问题,但在TNetHTTPClient.Get上却出现了这个问题。

在OnValidateServerCertificate中设置Accepted := True;会导致“获取服务器证书错误”。

你使用了什么解决方法?


0

无法在我三台运行Windows 7的测试计算机上使haveibeenpwned.com(HIBP)证书工作。其中一台是虚拟机,两台是物理机。

下载了HIBP数据,并将其中一部分作为测试导入到Amazon S3中,每个5个字符前缀作为S3公共对象。

现在,与上面相同的代码只需更改网址即可运行。

我仍然不知道为什么“获取服务器证书错误”会在Win 7上出现,但找到了可以接受的解决方法。

感谢所有查看此内容的人!


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