【问题标题】:Wininet SSL client authenticate oddnessWininet SSL 客户端验证奇怪
【发布时间】:2012-04-09 07:38:04
【问题描述】:

我有一个用于 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?

【问题讨论】:

    标签: delphi authentication ssl certificate wininet


    【解决方案1】:

    你可以做两件事:

    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

    希望对你有帮助。

    【讨论】:

    • 谢谢,我试试看! :) 我仍然觉得我的解决方案很奇怪,因为它与文档相反。我会切换到你的:)
    • 这仅在服务器允许匿名客户端身份验证时才有效!来自文档:If the user has not selected a certificate then anonymous client authentication will be attempted on the subsequent request.。第一个解决方案更有趣!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2015-08-07
    • 1970-01-01
    • 2017-05-18
    • 2014-09-15
    • 2014-11-13
    相关资源
    最近更新 更多