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

标签 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 源(柏林)“获取服务器证书时出错”,导致“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 10 机器上判断这是否是在 Win 7 上触发的。

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

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

谢谢你的帮助!

最佳答案

居然找到了解决方法,与Delphi无关。

来自 MS:

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/

关于Delphi TNetHTTPRequest/TNetHTTPClient 适用于 Win 10,但不适用于 Win 7,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50765476/

相关文章:

Delphi 7 - 将 Base 64 字符串解码到文件

delphi - 如何将文件从 Explorer Shell 拖放到 Delphi 应用程序中的 VirtualTreeView 控件中?

delphi - 捕捉 Audio Session 事件

python - Windows 上的 virtualenv 激活

.net - Shell 命名空间扩展无法在 Windows 7 中加载

ssl - 安装证书后 httpd 不启动

c++ - Boost.Asio/OpenSSL HTTPS GET 证书问题

delphi - 如何解决 Delphi XE 中大型 Enum 类型的 RTTI 大小问题?

windows-7 - IIS 7 主机 header 不起作用

wcf - 使用 MakeCert 创建有效的生产客户端证书以对 WCF 进行身份验证