delphi - Wininet SSL 客户端验证异常

标签 delphi authentication ssl certificate wininet

我有一个用于 HTTPs 切换到 Wininet 的爬虫。

这通常效果很好,但对于网站我会出错 ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED

示例代码:

vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
if vErrorNone = False then
  begin
    vErrorID := GetLastError;
    if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then
      begin
        // this error
      end
    ;
  end
;

然后我尝试了一个实验:

      TmpFakePointer := nil;
      vErrorNone :=
        InternetErrorDlg(
          GetDesktopWindow()
          ,
          HttpOpen_Request
          ,
          ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED
          ,
          0
          or FLAGS_ERROR_UI_FILTER_FOR_ERRORS
          or FLAGS_ERROR_UI_FLAGS_GENERATE_DATA
          or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS
          ,
          TmpFakePointer
        )
        = ERROR_SUCCESS
      ;
      if vErrorNone then
        begin
          vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
        end
      ;

但是,这里有两点很奇怪:

  • 1) 没有对话框显示
  • 2) 有效
  • 2.1) 第二个 HttpSendRequest 没有错误
  • 2.2) 返回有效数据

它发现上面的组合非常奇怪并且与文档相反。由于用户没有选择任何证书,为什么会这样呢?如果当无法显示对话框时 Wininet 回退到匿名客户端身份验证证书(我假设我给了它不正确的句柄来显示对话框?尽管如果我明确给它一个错误的句柄它会出错)有没有办法直接选择它没有调用 InternetErrorDlg?

最佳答案

您可以做两件事:

1:将证书错误显示给用户,让他决定是否继续。
2:忽略您收到的任何证书错误。

我将向您展示如何执行第二个选项:

当您收到 ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED 或任何其他证书错误时,您需要调用 InternetSetOptions 来告诉 wininet 它应该忽略该错误并继续。之后,您必须重新发送请求。

function SetToIgnoreCerticateErrors(var aErrorMsg: string): Boolean;
var
  vDWFlags: DWord;
  vDWFlagsLen: DWord;
begin
  Result := False;
  try
    vDWFlagsLen := SizeOf(vDWFlags);
    if not InternetQueryOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin
      aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to get wininet flags.' + GetWininetError;
      Exit;
    end;
    vDWFlags := vDWFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID or SECURITY_FLAG_IGNORE_CERT_CN_INVALID or SECURITY_FLAG_IGNORE_REVOCATION;
    if not InternetSetOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin
      aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to set wininet INTERNET_OPTION_SECURITY_FLAGS flag .' + GetWininetError;
      Exit;
    end;
    Result := True;
  except
    on E: Exception do begin
      aErrorMsg := 'Unknown error in SetToIgnoreCerticateErrors.' + E.Message;
    end;
  end;
end;


vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0);
if vErrorNone = False then
  begin
    vErrorID := GetLastError;
    if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then
    begin
      //call SetToIgnoreCerticateErrors
      //re-send the request 
    end
  end
end;

我已经从我的 wininet API 中提取了 SetToIgnoreCerticateErrors,它可能无法准确编译。

这些是步骤:

1 - 获取错误
2 - 检查错误是否为证书错误
3 - 如果是证书错误,他们会像我一样调用 InternetSetOption。
4 - 重新发送请求。

我不知道如何实现第一个选项“向用户显示证书错误并让他决定是否继续。”因为我从来不需要这样做。

另外,检查一下:How To Handle Invalid Certificate Authority Error with WinInet

希望对你有帮助。

关于delphi - Wininet SSL 客户端验证异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9861309/

相关文章:

delphi - Datasnap 与 SoapServer

delphi - 构建服务器: Best practices managing third party components?

c# - 如何将新创建的用户登录到站点

ruby-on-rails - 设计登录失败后重定向

amazon-web-services - Kafka Producer 中的 SSL 握手失败

Delphi:使用 RTTI 实例化的对象未调用重写方法

delphi - 如何在不丢失系统主题的情况下修复TPageControl背景颜色?

java - java中rest API的身份验证失败错误

c - SSL_CTX_set_cert_verify_callback 获取链表

http - 为什么无法从 HTTP Piwik 站点跟踪 HTTPS 站点?