Delphi TNetHTTPRequest/TNetHTTPClient 适用于 Win 10,但不适用于 Win 7

Delphi TNetHTTPRequest/TNetHTTPClient Works on Win 10, but not Win 7

在源代码下方添加了新的详细信息。

有一个问题是 Delphi Internet 代码可以在 Win 10 上运行,但不能在 Win 7 上运行。我正在尝试将一个小项目连接到 haveibeenpwned.com (HIBP)。 Win 7 returns“获取服务器证书时出错。”

为了尝试修复 Win 7 问题,我向 TNetHTTPRequest 和 TNetHTTPClient 添加了一个 OnValidateServerCertificate。在Win 10和Win 7中,似乎都没有调用OnValidateServerCertificate。

我在2台Win 10电脑和2台Win 7电脑上测试过,结果相同。 1) 为什么 Win 7 return “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.

link https://api.pwnedpasswords.com/range/55555(示例前 5 个字符哈希)在 IE 中 return 出现证书错误。我在 Win 7 Internet 选项高级中添加了 TLS 1.1 和 1.2。这允许浏览器工作。

程序仍然无法运行。所以我 grepped Delphi 来源(柏林)"Error getting Server Certificate" 导致 "SNetHttpGetServerCertificate"。在 System.Net.HttpClient:

procedure THTTPClient.DoValidateServerCertificate(LRequest: THTTPRequest);

...

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

这似乎是唯一可以引发此异常的地方。不幸的是,在那里设置一个断点(即使调试 DCU 打开)从未被击中。

其中可能存在ServerCertificateInvalid TWinHTTPClient.DoExecuteRequest 我走过的时候经过。如果这是在 Win 7 上触发的,我无法从我的 Win 10 机器上判断。

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

也许某些东西与此配置不兼容,Delphi(柏林)和 Win 7?

感谢您的帮助!

无法获得在我的 3 台 Win 7 测试计算机上运行的 haveibeenpwned.com (HIBP) 证书。一台虚拟机,两台物理机。

下载 HIBP 数据并将其中的一些作为测试导入 Amazon S3,每个 5 个字符前缀作为 S3 public 对象。

现在,与上面相同的代码只需要更改 url。

我仍然不知道为什么 "Error getting Server Certificate" 一直出现在 Win 7 上,但找到了一个可以接受的解决方法。

感谢所有看过这篇文章的人!

同样的问题在这里访问 https://www.geocaching.com/account/login 在 windows 10 中工作没有问题,但在 TNetHTTPClient.Get 上得到 "Server Certificate Invalid or not Present"。

设置已接受:=真;在 OnValidateServerCertificate 上将给出 "Error getting Server Certificate".

您使用了什么解决方法?

实际找到解决方案,与Delphi无关。

来自女士:

Applications and services that are written by using WinHTTP for Secure Sockets Layer (SSL) connections that use the WINHTTP_OPTION_SECURE_PROTOCOLS flag can't use TLS 1.1 or TLS 1.2 protocols. This is because the definition of this flag doesn't include these applications and services.

This update adds support for DefaultSecureProtocols registry entry that allows the system administrator to specify which SSL protocols should be used when the WINHTTP_OPTION_SECURE_PROTOCOLS flag is used.

This can allow certain applications that were built to use the WinHTTP default flag to be able to leverage the newer TLS 1.2 or TLS 1.1 protocols natively without any need for updates to the application.

修复:

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