2012-03-29 25 views
15

Chúng tôi có ứng dụng ASP.NET MVC 2 (.NET 4) chạy trên Windows Azure (phiên bản hệ điều hành mới nhất 2.x) với hai phiên bản vai trò web.Tại sao HttpAntiForgeryException xảy ra ngẫu nhiên ngay cả với một Khóa Máy tĩnh?

Chúng tôi sử dụng mã thông báo chống giả mạo được cung cấp bởi MVC cho tất cả các yêu cầu POST và chúng tôi đã đặt Khóa máy tĩnh trong web.config, vì vậy mọi thứ hoạt động trên nhiều máy và khởi động lại. 99,9% các trường hợp nó hoạt động hoàn hảo.

Hiện tại, tuy nhiên, chúng tôi đăng nhập một HttpAntiForgeryException, với thông báo "Mã thông báo chống giả mạo không được cung cấp hoặc không hợp lệ".

Tôi biết sự cố có thể là cookie không được phép trong trình duyệt, nhưng chúng tôi đã xác minh rằng cookie và cookie được bật và được gửi đi qua lại chính xác.

Lỗi xảy ra với nhiều trình duyệt khác nhau và rõ ràng gây ra sự cố cho người dùng vì họ phải lặp lại thao tác hoặc họ có thể mất một số dữ liệu. Đủ để nói, chúng tôi đã không thể tái tạo vấn đề cục bộ, nhưng nó chỉ xảy ra trên Windows Azure.

Tại sao điều đó lại xảy ra? Làm thế nào chúng ta có thể tránh nó?

+0

Tôi đã kiểm tra với các nhân viên bảo mật (trong nhóm MVC) và Darin có thể đúng - tên người dùng có thể đã thay đổi. – RickAndMSFT

Trả lời

0

Có một số tùy chọn cho những gì bạn có thể thử. Bạn có thể thử truy cập từ xa vào máy và xem nhật ký sự kiện để xem liệu bạn có thể nhận thêm thông tin từ đó liên quan đến nơi xảy ra điều này hay không. Nếu điều đó không giúp ích gì, bạn có thể sử dụng DebugDiag hoặc một số công cụ khác để nắm bắt một kết xuất của quá trình (DebugDiag sẽ cho phép bạn chụp một lần tại thời điểm ngoại lệ cụ thể này). Và sau đó nhìn vào đó để xem những gì đang xảy ra.

Nếu bạn không thể tìm ra nó từ đó, bạn luôn có thể tạo trường hợp hỗ trợ với Microsoft để giúp bạn điều tra.

7

Mã thông báo chống giả mạo chứa tên người dùng của người dùng hiện được kết nối khi nó được phát ra. Và khi xác minh tính hợp lệ của nó, người dùng hiện được kết nối được kiểm tra với người dùng được sử dụng khi mã thông báo được phát ra. Vì vậy, ví dụ nếu bạn có một hình thức mà trong đó người dùng chưa được xác thực và bạn phát ra một mã thông báo chống giả mạo, sẽ không có bất kỳ tên người dùng nào được lưu trữ trong đó. Nếu khi bạn gửi biểu mẫu bạn xác thực người dùng thì mã thông báo sẽ không còn hợp lệ nữa. Tương tự áp dụng cho đăng xuất.

Sau đây là cách phương pháp Validate trông giống như:

public void Validate(HttpContextBase context, string salt) 
{ 
    string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null); 
    string str2 = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath); 
    HttpCookie cookie = context.Request.Cookies[str2]; 
    if ((cookie == null) || string.IsNullOrEmpty(cookie.Value)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data = this.Serializer.Deserialize(cookie.Value); 
    string str3 = context.Request.Form[antiForgeryTokenName]; 
    if (string.IsNullOrEmpty(str3)) 
    { 
     throw CreateValidationException(); 
    } 
    AntiForgeryData data2 = this.Serializer.Deserialize(str3); 
    if (!string.Equals(data.Value, data2.Value, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
    string username = AntiForgeryData.GetUsername(context.User); 
    if (!string.Equals(data2.Username, username, StringComparison.OrdinalIgnoreCase)) 
    { 
     throw CreateValidationException(); 
    } 
    if (!string.Equals(salt ?? string.Empty, data2.Salt, StringComparison.Ordinal)) 
    { 
     throw CreateValidationException(); 
    } 
} 

Một cách tốt để gỡ lỗi này là để biên dịch lại ASP.NET MVC từ mã nguồn của nó và đăng nhập một cách chính xác, trong đó các trường hợp nếu bạn nhập khi trừ được ném.

+0

Các nhân viên bảo mật trong nhóm ASP.NET MVC đồng ý, tên người dùng có thể đã thay đổi. Bây giờ MVC là mã nguồn mở, bạn có thể xây dựng một nhánh chẩn đoán. Một lưu ý nhỏ, Mã thông báo AF KHÔNG chứa tên người dùng - mã hiển thị tên người dùng đến từ mã thông báo biểu mẫu chứ không phải mã thông báo cookie. – RickAndMSFT

+0

Vấn đề là chúng tôi không sử dụng xác thực ASP.NET và chúng tôi không bao giờ đặt người dùng/danh tính. Tên người dùng có thể tự thay đổi (miễn là ứng dụng chạy dưới dạng Dịch vụ mạng trên Azure)? –

+0

Bạn đã thử biên dịch lại ASP.NET MVC từ mã nguồn và truy tìm trong trường hợp xác minh antiforgery không thành công? –

15

Tôi cũng gặp phải sự cố này gần đây và tìm thấy hai nguyên nhân.

1. Trình duyệt phục hồi phiên cuối cùng trên mở cho trang đó được lưu trữ

Nếu bạn có một trang đó là cachable mà thực hiện một bưu điện đến máy chủ của bạn (ví dụ antiforgery sẽ được trên) và người dùng có họ trình duyệt được thiết lập để khôi phục phiên cuối cùng khi khởi động (tùy chọn này tồn tại trong chrome) trang sẽ được hiển thị từ bộ nhớ cache. Tuy nhiên, cookie xác minh yêu cầu sẽ không có ở đó vì nó là cookie phiên trình duyệt và bị hủy khi trình duyệt bị đóng. Vì cookie đã biến mất, bạn sẽ nhận được ngoại lệ chống giả mạo. Giải pháp: Trả lại tiêu đề phản hồi để trang không được lưu trong bộ nhớ cache (tức là Cache-Control: private, no-store).

2.Điều kiện cuộc đua nếu mở nhiều tab khi khởi động đến trang web của bạn

Trình duyệt có tùy chọn mở một bộ tab khi khởi động. Nếu nhiều hơn một trong số các trang web này truy cập trang web của bạn trả lại cookie xác minh yêu cầu, bạn có thể đạt đến điều kiện chủng tộc khi cookie xác minh yêu cầu bị ghi đè. Điều này xảy ra vì nhiều yêu cầu truy cập máy chủ của bạn từ người dùng không có tập hợp cookie xác minh yêu cầu. Yêu cầu đầu tiên được xử lý và đặt cookie xác minh yêu cầu. Tiếp theo yêu cầu thứ hai được xử lý, nhưng nó không gửi cookie (chưa được đặt vào thời điểm yêu cầu) để máy chủ tạo một yêu cầu mới. Cái mới sẽ ghi đè lên cái đầu tiên và bây giờ trang đó sẽ nhận được một ngoại lệ yêu cầu antiforgery khi nó tiếp theo thực hiện một bài đăng. Khung MVC không xử lý kịch bản này. Lỗi này đã được báo cáo cho nhóm MVC tại Microsoft.

+0

Tôi cũng thấy điều kiện 2. Nó chỉ xảy ra cho người dùng đầu tiên. Khi trang đã tải cho người dùng đầu tiên đó, điều đó sẽ không xảy ra nữa. – GnomeCubed

1

Tôi có một vài ứng dụng web MVC3 có được điều này khá thường xuyên. Phần lớn trong số họ là vì khách hàng không gửi một cơ thể POST. Và hầu hết trong số này là IE8 vì một số lỗi với yêu cầu ajax trước một bài đăng biểu mẫu thông thường. Có một hotfix cho IE mà dường như để giải quyết các triệu chứng, trong đó loại chứng minh rằng nó là một lỗi khách hàng trong những trường hợp

http://support.microsoft.com/?kbid=831167

Có một vài cuộc thảo luận về các vấn đề xung quanh các trang web, không có gì quá hữu ích mặc dù , chắc chắn tôi không muốn gây rối với timeouts giữ-sống mà là một gợi ý "giải pháp" ở một số nơi ...

https://www.google.com/search?q=ie8+empty+post+body

tôi chưa bao giờ có khả năng tái tạo nó với nhiều nỗ lực để thiết lập lại các kết nối giữa POSTS vì vậy tôi sợ rằng tôi không có một giải pháp cho trường hợp các cơ quan POST trống của IE. Cách chúng tôi đã giảm thiểu nó một chút là đảm bảo rằng chúng tôi không bao giờ sử dụng phương thức POST khi chỉ truy xuất dữ liệu qua ajax.

Nếu bạn đăng nhập yêu cầu đầy đủ, hãy kiểm tra xem cơ thể POST có trống không và nếu có, nó có thể là một trình duyệt cũ hơn. Và tôi không có nghĩa là Content-Length: 0, nó thường sẽ có Content-Length có vẻ đúng trong các tiêu đề nhưng sẽ không có gì sau các tiêu đề trong yêu cầu.

Vấn đề như một tổng thể vẫn là một bí ẩn đối với tôi mặc dù bởi vì chúng tôi vẫn nhận được ngoại lệ không thường xuyên, nơi có một cơ thể POST hoàn chỉnh. Tên người dùng của chúng tôi không bao giờ thay đổi và các khóa của chúng tôi cũng là tĩnh, tôi chưa thử thêm gỡ lỗi vào nguồn, nếu tôi nhận được thông tin đó, tôi sẽ báo cáo các phát hiện của tôi.

0

Tôi đã gặp phải các sự cố tương tự với mã chống giả mạo do nhà tôi sản xuất, khái niệm này rất giống với cơ chế MVC. Chủ yếu là vấn đề dường như xảy ra bởi vì các trình duyệt hiện đại xuất hiện sẵn sàng hiển thị các bản sao được lưu trong bộ nhớ cache của các trang được chỉ định là không được lưu trong bộ nhớ cache.

Tôi đã thử tất cả các kết hợp của chỉ thị trang không có bộ nhớ cache, nhưng đôi khi tôi vẫn nhận được các trang được lưu trong bộ nhớ cache được hiển thị.

Tôi nhận thấy rằng giải pháp tốt hơn là móc sự kiện onbeforeunload cho trang và xóa rõ ràng giá trị của trường nhập ẩn giữ giá trị mã thông báo trong DOM.

Nếu bản sao được lưu trong bộ nhớ cache của một trang được tải, nó có vẻ chứa giá trị trường nhập đã xóa. sau đó tôi thử nghiệm cho điều này trong các tài liệu chức năng sẵn sàng và tải lại trang nếu cần thiết:

window.location.reload(true); 

Dường như làm việc khá hiệu quả, và tôi nghi ngờ nó có thể cho mã chống giả mạo MVC quá.

Các vấn đề liên quan