2012-03-25 39 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