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

时间:2018-06-08 17:08:51

标签: delphi windows-7 ssl-certificate

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

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

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

我已经测试了2台Win 10计算机和2台Win 7计算机,结果相同。 1)为什么Win 7返回“获取服务器证书时出错? 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 Options,Advanced中添加了TLS 1.1和1.2。这使浏览器可以工作。

程序仍无效。所以我抓住了Delphi Source(柏林)“获得服务器证书的错误”,这导致了“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 个答案:

答案 0 :(得分:1)

实际上找到了与Delphi无关的解决方案。

从MS:

  

使用WinHTTP for Secure编写的应用程序和服务   使用以下内容的套接字层(SSL)连接   WINHTTP_OPTION_SECURE_PROTOCOLS标志不能使用TLS 1.1或TLS 1.2   协议。这是因为此标志的定义不包括   这些应用程序和服务。

     

此更新增加了对DefaultSecureProtocols注册表项的支持   允许系统管理员指定哪些SSL协议   当使用WINHTTP_OPTION_SECURE_PROTOCOLS标志时,应使用

。      

这可以允许某些已构建的应用程序使用WinHTTP   默认标志,以便能够利用较新的TLS 1.2或TLS 1.1   本地协议,无需更新应用程序。

修复:

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

答案 1 :(得分:0)

无法获得hasibeenpwned.com(HIBP)证书以在我的3台Win 7测试计算机上运行。一个VM,2个物理。

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

现在,与上面相同的代码仅适用于更改的网址。

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

感谢所有看过这个的人!

答案 2 :(得分:0)

此处遇到相同的问题,https://www.geocaching.com/account/login 在Windows 10中正常工作,但在TNetHTTPClient.Get上显示“服务器证书无效或不存在”。

接受设置:= True;在OnValidateServerCertificate上将显示“获取服务器证书时出错”。

您使用了什么解决方法?