2010-05-26 15 views
19

Thông thường, khi một trang web yêu cầu bạn đăng nhập trước khi bạn có thể truy cập vào một trang nhất định được đưa đến màn hình đăng nhập và sau khi tự xác thực thành công, bạn được chuyển hướng trở lại trang được yêu cầu ban đầu. Điều này là rất tốt cho khả năng sử dụng - nhưng không cẩn thận, tính năng này có thể dễ dàng trở thành một lỗ hổng open redirect.Cách tránh lỗ hổng chuyển hướng mở và chuyển hướng an toàn khi đăng nhập thành công (Gợi ý: Mã mặc định ASP.NET MVC 2 dễ bị tổn thương)

Đáng buồn thay, cho một ví dụ về lỗ hổng này, lựa chọn nào tốt hơn hành động đăng nhập mặc định được cung cấp bởi ASP.NET MVC 2:

[HttpPost] 
public ActionResult LogOn(LogOnModel model, string returnUrl) 
{ 
    if (ModelState.IsValid) { 
     if (MembershipService.ValidateUser(model.UserName, model.Password)) { 
      FormsService.SignIn(model.UserName, model.RememberMe); 

      if (!String.IsNullOrEmpty(returnUrl)) { 
       return Redirect(returnUrl); // open redirect vulnerability HERE 
      } else { 
       return RedirectToAction("Index", "Home"); 
      } 

     } else { 
      ModelState.AddModelError("", "User name or password incorrect..."); 
     } 
    } 

    return View(model); 
} 

Nếu người dùng được xác thực thành công, họ đang chuyển hướng đến "ReturnUrl" (nếu nó được cung cấp thông qua việc gửi biểu mẫu đăng nhập).

Dưới đây là một cuộc tấn công đơn giản ví dụ (một trong nhiều người, trên thực tế) mà khai thác lỗ hổng này:

  1. Attacker, giả vờ là ngân hàng của nạn nhân, gửi một email để nạn nhân có chứa một liên kết, như thế này: http://www.mybank.com/logon?returnUrl=http://www.badsite.com
  2. Đã được dạy để xác minh tên miền ENTIRE (ví dụ: google.com = GOOD, google.com.as31x.example.com = BAD), nạn nhân biết liên kết là OK - không có bất kỳ tên miền phụ phức tạp nào lừa đảo đang diễn ra.
  3. Nạn nhân nhấp vào liên kết, thấy thực tế trang web ngân hàng quen thuộc của họ và được yêu cầu đăng nhập
  4. nạn nhân đăng nhập vào và sau đó được chuyển đến http://www.badsite.com được thực hiện để trông giống hệt như trang web ngân hàng của nạn nhân, vì vậy nạn nhân không biết anh ấy đang ở trên một trang web khác.
  5. http://www.badsite.com nói điều gì đó như "Chúng tôi cần cập nhật hồ sơ của mình - vui lòng nhập một số thông tin cực kỳ cá nhân bên dưới: [ssn], [address], [phone number], v.v ..."
  6. nạn nhân, vẫn nghĩ ông là trên trang web ngân hàng của mình, rơi cho mưu đồ và cung cấp kẻ tấn công với các thông tin

Bất kỳ ý tưởng về làm thế nào để duy trì chuyển hướng-on-thành-đăng nhập này chức năng chưa tránh open- chuyển hướng dễ bị tổn thương?

Tôi đang hướng về tùy chọn tách thông số "returnUrl" thành bộ phận điều khiển/tác vụ và sử dụng "RedirectToRouteResult" thay vì chỉ đơn giản là "Chuyển hướng". Cách tiếp cận này có mở bất kỳ lỗ hổng mới nào không?

Cập nhật

Bằng cách giới hạn bản thân mình để điều khiển các tuyến đường/hành động, tôi không thể chuyển hướng đến các tuyến đường tùy chỉnh (ví dụ /backend/calendar/2010/05/21). Tôi biết rằng bằng cách chuyển nhiều tham số hơn cho hành động LogOn, tôi có thể làm cho nó hoạt động, nhưng tôi cảm thấy như tôi sẽ luôn luôn xem xét lại phương pháp này - giữ nó cập nhật với lược đồ định tuyến của chúng tôi. Vì vậy, thay vì tách returnUrl thành các phần điều khiển/hành động, tôi đang giữ returnUrl dưới dạng và phân tích cú pháp để đảm bảo nó chỉ chứa một đường dẫn tương đối (ví dụ: /users/1) và không phải là đường dẫn tuyệt đối (ví dụ: http://www.badsite.com/users/1).Đây là mã Tôi đang sử dụng:

private static bool CheckRedirect(string url) { 
    try { 
     new Uri(url, UriKind.Relative); 
    } 
    catch (UriFormatException e) { 
     return false; 
    } 

    return true; 
} 

Side lưu ý: Tôi biết mở chuyển hướng này có thể không có vẻ là một vấn đề lớn so với những cái tên như XSS và CSRF, nhưng chúng tôi phát triển là điều duy nhất bảo vệ khách hàng của chúng tôi khỏi những kẻ xấu - bất cứ điều gì chúng tôi có thể làm để làm cho công việc của kẻ xấu khó hơn là một chiến thắng trong cuốn sách của tôi.

Cảm ơn, Brad

+0

Nếu bộ nhớ phục vụ, ReturnURL phải phù hợp với một trong những tuyến đường của bạn, hoặc điều sẽ YSOD. Nhưng tôi có thể sai. Bạn đã thử nghiệm điều này để chứng minh nó là một lỗ hổng? –

+0

Tôi vừa thử nghiệm nó. Đúng rồi. Một câu hỏi khác có liên quan [ở đây] (http://stackoverflow.com/questions/2782710/what-is-it-about-the-default-asp-net-mvc-accountcontroller-code-that-some-hate) –

+0

Nếu nó sẽ làm cho bạn cảm thấy tốt hơn, tôi khá chắc chắn rằng 'Redirect' không * không * làm một POST, nhưng chỉ GET. Nhưng tôi không cho rằng điều đó sẽ giúp bạn nếu thông tin nhạy cảm được truyền trong URL chuyển hướng dưới dạng tham số. –

Trả lời

0

Chừng nào bạn sử dụng một trong những biến thể của Redirect có sử dụng bộ điều khiển và hành động các tham số hoặc một tên tuyến đường, bạn nên có alright, miễn là bạn có kiểm soát bảo mật đầy đủ về phương pháp điều khiển của bạn.

Khái niệm là, bất cứ điều gì bạn sử dụng cho chuyển hướng của mình đều phải đi qua công cụ định tuyến và được xác thực bằng cách khớp một tuyến đường.

Nhưng tôi nghi ngờ rằng lỗ hổng thực là Cross-Site Scripting. Trừ khi người dùng độc hại của bạn có thể tiêm một số Javascript vào trang, họ không có cách nào để thao tác Url trả về hoặc bất kỳ tham số nào của nó (vì bạn có thể kiểm soát tất cả mã máy chủ và trình duyệt).

+1

Vui lòng xem cập nhật của tôi - tôi đã chọn phân tích cú pháp returnUrl, đảm bảo rằng nó không phải là URL tuyệt đối. –

1

Bạn luôn có thể lưu bản ghi của trang trước bằng TempData khi người dùng không được xác thực và sử dụng để chuyển hướng đến trang trước thay vì tham số url.

+0

Tôi không nghĩ rằng điều này sẽ làm việc - TempData chỉ tồn tại thông qua 1 chuyển hướng. Trong trường hợp này, một người cố gắng nhấn một URL được bảo mật khiến trình duyệt của họ chuyển hướng đến thông tin đăng nhập. Sau khi nhập tên người dùng/mật khẩu, họ đăng nhập và được chuyển hướng trở lại trang được yêu cầu ban đầu. Đây là hai chuyển hướng, vì vậy TempData không thể hoạt động. Một ý tưởng tốt hơn có thể là đính kèm URL chuyển hướng vào Phiên? –

3

Vâng đây là lỗ hổng bảo mật. Trước khi chuyển hướng, bạn cần phải kiểm tra thông số chuỗi returnUrl bằng cách chuyển nó tới đối tượng Uri và đảm bảo rằng tên miền đích giống với miền yêu cầu. Bạn cũng nên tính đến trường hợp khi returnUrl là địa chỉ tương đối như /admin. Không có vấn đề gì trong trường hợp này vì chuyển hướng sẽ đến cùng một ứng dụng.

+0

Cảm ơn đề xuất này - dường như vẫn hoạt động tốt! Vui lòng xem cập nhật của tôi cho câu hỏi ban đầu để biết chi tiết về cách tôi phân tích cú pháp returnUrl. –

9

Jon Galloway đã viết một article với giải pháp cho MVC 2 (và 1).

Dưới đây là đoạn mã mà nên giúp đỡ với vấn đề của bạn:

private bool IsLocalUrl(string url) 
{ 
    if (string.IsNullOrEmpty(url)) 
    { 
     return false; 
    } 

    Uri absoluteUri; 
    if (Uri.TryCreate(url, UriKind.Absolute, out absoluteUri)) 
    { 
     return String.Equals(this.Request.Url.Host, absoluteUri.Host, 
        StringComparison.OrdinalIgnoreCase); 
    } 
    else 
    { 
     bool isLocal = !url.StartsWith("http:", StringComparison.OrdinalIgnoreCase) 
      && !url.StartsWith("https:", StringComparison.OrdinalIgnoreCase) 
      && Uri.IsWellFormedUriString(url, UriKind.Relative); 
     return isLocal; 
    } 
} 
+0

Đây là khóa học tương tự như bản cập nhật của bạn, mà không phải chịu phí ngoại lệ. –

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