2015-04-28 25 views
29

在這裏頗爲神祕。我有一個使用Windows身份驗證的ASP.NET MVC 4 Web應用程序,已經維護了18個月以上,沒有問題。最近,它被部署到一個新的網站,我遇到了以下非常奇怪的行爲。從一個AJAX POST獲取NTLM挑戰只需一頁

我正在使用jQuery 1.8.2 $.ajax調用POST數據到服務器端點來更新數據。這工作得很好,除了在一個頁面上,AJAX POST觸發新的NTLM協商。 Chrome,IE和Firefox中也出現同樣的問題。儘管這一問題是在所有的瀏覽器一樣,它體現在略微不同的方式:

  • 的Firefox:從服務器接收到一個401質詢響應,並提出了一個用戶名/密碼對話框中無限循環要求的憑證。取消憑證檢查會導致請求失敗並顯示未經授權的響應。
  • IE:服務器沒有響應,請求狀態在網絡監視器中顯示爲「(中止)」
  • Chrome:服務器沒有響應,請求狀態在網絡監視器中顯示「(失敗)」 。

核心問題似乎是Connection: keep-alive標頭沒有與有問題的AJAX請求一起發送,但在其他情況下。但是,底層JavaScript代碼幾乎相同,並且AJAX調用在也設置爲使用Windows身份驗證的開發環境中正常工作。

此外,試圖在beforeSend回調中設置Connection請求標頭沒有任何效果。非常感謝您對問題根源的任何洞察,或解決兩個AJAX POST之間存在差異的方法。

工作代碼和請求頭

$.ajax({ 
    url: url, 
    type: "POST", 
    data: $("#myForm").serialize(), 
    cache: false, 
    success: function (response) { 
    } 
}); 


Accept:*/* 
Accept-Encoding:gzip, deflate 
Accept-Language:en-US,en;q=0.8 
Connection:keep-alive 
Content-Length:621 
Content-Type:application/x-www-form-urlencoded; charset=UTF-8 
Host:www.xxx.yyy.zzz 
Origin:http://www.xxx.yyy.zzz 
Referer:http://www.xxx.yyy.zzz/app/resource/path 
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 
X-Requested-With:XMLHttpRequest 

失敗代碼和請求頭

$.ajax({ 
    url: url, 
    type: "POST", 
    data: data, 
    cache: false, 
    success: function (data, status, xhr) { 
    } 
}); 

WARN: Provisional headers are shown 
Accept:*/* 
Content-Type:application/x-www-form-urlencoded; charset=UTF-8 
Origin:http://www.xxx.yyy.zzz 
Referer:http://www.xxx.yyy.zzz/app/resource/item/1 
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 
X-Requested-With:XMLHttpRequest 

我也看了在Chrome chrome://net-internals/#events觀衆網絡的過程。以下是失敗請求中的事件日誌與偏離成功日誌的位置的關係。如果失敗的請求獲得「HTTP/1.1 401 Unauthorized」,成功的請求將獲得「HTTP/1.1 200 OK」響應,可能是由於存在Connection: keep-alive標頭。

2303: URL_REQUEST 
Start Time: 2015-04-28 13:53:41.788 

t=14736 [st= 0] +REQUEST_ALIVE [dt=71] 
t=14736 [st= 0] URL_REQUEST_DELEGATE [dt=0] 
t=14736 [st= 0] +URL_REQUEST_START_JOB [dt=70] 
        --> load_flags = 2688000 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT) 
       --> method = "POST" 
       --> priority = "LOW" 
       --> upload_id = "0" 
       --> url = "http://..." 
t=14736 [st= 0]  URL_REQUEST_DELEGATE [dt=0] 
t=14736 [st= 0]  HTTP_CACHE_GET_BACKEND [dt=0] 
t=14736 [st= 0]  URL_REQUEST_DELEGATE [dt=0] 
t=14736 [st= 0]  +HTTP_STREAM_REQUEST [dt=0] 
t=14736 [st= 0]  HTTP_STREAM_REQUEST_BOUND_TO_JOB 
         --> source_dependency = 2305 (HTTP_STREAM_JOB) 
t=14736 [st= 0]  -HTTP_STREAM_REQUEST 
t=14736 [st= 0]  +HTTP_TRANSACTION_SEND_REQUEST [dt=0] 
t=14736 [st= 0]  HTTP_TRANSACTION_SEND_REQUEST_HEADERS 
         --> POST ... HTTP/1.1 
         Host: www.xxx.yyy.zzz 
         Connection: keep-alive 
         Content-Length: 105 
         Accept: */* 
         Origin: http://www.xxx.yyy.zzz 
         User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 
         X-Requested-With: XMLHttpRequest 
         Content-Type: application/x-www-form-urlencoded; charset=UTF-8 
         Referer: http://www.xxx.yyy.zzz/app/resource/item/1 
         Accept-Encoding: gzip, deflate 
         Accept-Language: en-US,en;q=0.8 
t=14736 [st= 0]  HTTP_TRANSACTION_SEND_REQUEST_BODY 
         --> did_merge = true 
         --> is_chunked = false 
         --> length = 105 
t=14736 [st= 0]  -HTTP_TRANSACTION_SEND_REQUEST 
t=14736 [st= 0]  +HTTP_TRANSACTION_READ_HEADERS [dt=0] 
t=14736 [st= 0]  HTTP_STREAM_PARSER_READ_HEADERS [dt=0] 
t=14736 [st= 0]  HTTP_TRANSACTION_READ_RESPONSE_HEADERS 
        --> HTTP/1.1 401 Unauthorized 
         Content-Type: text/html 
         Server: Microsoft-IIS/7.5 
         WWW-Authenticate: Negotiate 
         WWW-Authenticate: NTLM 
         X-Powered-By: ASP.NET 
         X-UA-Compatible: IE=9 
         Date: Tue, 28 Apr 2015 18:53:41 GMT 
         Content-Length: 1293 

編輯

與從控制檯不同請求播放周圍給出的結果的下表(下鉻)。目前的基本URL是http://IPAddress /app/topic/item和所有測試只需執行$.ajax({ url: url, type: 'POST' })

+--------------------------------------+----------------------------+ 
| URL        | Response     | 
+--------------------------------------+----------------------------+ 
| http://IP/app/topic/item/1/subitem/1 | net::ERR_INVALID_HANDLE | 
| //IP/app/topic/item/1/subitem/1  | net::ERR_INVALID_HANDLE | 
| /app/topic/item/1/subitem/1   | net::ERR_INVALID_HANDLE | 
| 1/subitem/1       | net::ERR_INVALID_HANDLE | 
| 1/foo        | 404 (Not Found) [expected] | 
| 1         | 302 (Redirect) [expected] | 
+--------------------------------------+----------------------------+ 

因爲錯誤影響一個控制器的POST操作方法的一個子集,我最初以爲這是一個服務器端的問題,但在發現缺少Connection標題的問題後,它實際上似乎是客戶端問題。問題究竟如何觸發對我來說仍然是一個謎。

我也確認了工作頁面和問題頁面的響應標題是相同的。最相關的是,在兩種情況下總是返回Persistent-Auth: true標題。

+0

您是否嘗試過從'ajax'調用執行'error'處理程序?你可能在這裏得到一些額外的信息? – christiandev

+0

@christiandev是的。 Chrome返回一個net :: ERR_INVALID_HANDLE錯誤代碼,IE的錯誤代碼爲12019,記錄爲ERROR_INTERNET_INCORRECT_HANDLE_STATE。 Firefox也會報告「無效句柄」。 – Lucas

+0

另一件事,我添加了匹配所有[POST]路由的[GET]路由,以防萬一這是對IE和IWA已知的GET-before-POST問題的奇怪表現形式。這沒有效果。 – Lucas

回答

1

一些亂撞:

  • 當你請求一個角色,是不是在當前登錄的用戶的索賠會出現這種情況。請確認,如果您使用的是[Authorize(Roles = "xyz")],則當前用戶實際上具有該角色。

  • 不清楚您的應用程序是否使用cookie進行身份驗證。如果是的話,你應該看到它的請求。你是否爲每個請求設置了withCredentials: true

+0

你可能會在這裏做點什麼。我們有一個安全設置,利用我們自己的ActionFilter屬性,因此它可能是與用戶角色映射有關的後端數據問題。感謝您的建議。 – Lucas

+0

沒有運氣。用戶具有正確的角色,事實上'AuthorizeAttribute'被設置爲全局過濾器,所以如果這是問題,所有的請求都會失敗。另外,使用Glimpse,AJAX請求甚至不會碰到.Net管道;它立即中止。我在開發環境和生產環境之間唯一的區別是,問題發生在IIS 7.5上,而不是在本地IIS 8.5上。我會嘗試在IIS Express 7.5下本地運行,看看是否會重現此問題。 – Lucas

+0

@Lucas您應該在轉儲中從Negotiate頭文件中編輯MIME。它可以被解碼以獲取你可能不想暴露的信息。 – JamieSee

0

導致NTLM挑戰的操作方法中發生了什麼?您確定這些特定的操作方法沒有通過需要驗證的代理訪問另一臺服務器或互聯網嗎?在您的開發環境中,您的用戶或在IIS上運行應用程序池的用戶可能具有必要的權限,但服務器上的用戶可能不具有這些權限。

ASP.NET不會拋出明確的與安全有關的異常,而會將其轉換爲返回給客戶端的NTLM質詢,如果憑證無效,則會將其轉換爲401,而不是包含引導您到達點服務器帳戶沒有足夠的權限...