2012-03-25 109 views
1

我有一个爬虫,HTTPs切换到Wininet。Wininet SSL客户端验证奇怪

这通常效果很好,但对于一个网站,我得到错误 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?

回答

2

有两件事情可以做:

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

我希望它可以帮助你。

+0

谢谢,我会试试看!:)我仍然发现我的解决方案很奇怪,因为它与文档相反。我会切换到你的:) – Tom 2012-04-05 11:49:15

+0

刚刚测试过的解决方案,它的工作原理!谢谢:) – Tom 2012-04-05 12:21:22

+0

我很高兴我可以帮助你。 – 2012-04-05 12:28:29