Как избежать уязвимости открытого перенаправления и безопасного перенаправления при успешном входе в систему (СОВЕТ: уязвим код ASP.NET MVC 2 по умолчанию) - PullRequest
19 голосов
/ 26 мая 2010

Обычно, когда сайт требует, чтобы вы вошли в систему, прежде чем вы сможете получить доступ к определенной странице, вы попадете на экран входа в систему и после успешной аутентификации вы будете перенаправлены обратно на первоначально запрошенную страницу. Это очень удобно для удобства использования, но без тщательного изучения эта функция может легко стать уязвимостью open redirect .

К сожалению, в качестве примера этой уязвимости смотрите не дальше, чем действие LogOn по умолчанию, предоставляемое 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);
}

Если пользователь успешно прошел аутентификацию, он перенаправляется на «returnUrl» (если это было предоставлено посредством отправки формы входа в систему).

Вот простой пример атаки (одной из многих, на самом деле), которая использует эту уязвимость:

  1. Атакующий, притворяющийся банком жертвы, отправляет жертве электронное письмо со ссылкой, например: http://www.mybank.com/logon?returnUrl=http://www.badsite.com
  2. После того, как учили проверять ВСЕ доменное имя (например, google.com = GOOD, google.com.as31x.example.com = BAD), жертва знает, что ссылка в порядке - никаких хитростей Фишинг домена продолжается.
  3. Жертва нажимает на ссылку, видит свой фактический знакомый банковский сайт и получает запрос на вход
  4. Жертва входит в систему и впоследствии перенаправляется на http://www.badsite.com, который выглядит как веб-сайт банка жертвы, поэтому жертва не знает, что он сейчас на другом сайте.
  5. http://www.badsite.com говорит что-то вроде: «Нам нужно обновить наши записи. Пожалуйста, введите ниже крайне личную информацию: [ssn], [адрес], [номер телефона] и т. Д.»
  6. Жертва, все еще думая, что он находится на своем банковском веб-сайте, падает на уловку и предоставляет злоумышленнику информацию

Есть какие-нибудь идеи о том, как сохранить эту функцию перенаправления при успешном входе в систему, но избежать уязвимости открытого перенаправления?

Я склоняюсь к возможности разделения параметра «returnUrl» на части контроллера / действия и использую «RedirectToRouteResult» вместо простого «Redirect». Раскрывает ли этот подход какие-либо новые уязвимости?

Обновление

Ограничив себя маршрутами контроллера / действия, я не могу перенаправить на пользовательские маршруты (например, /backend/calendar/2010/05/21). Я знаю, что, передав больше параметров в действие LogOn, я мог бы заставить его работать, но я чувствую, что всегда буду пересматривать этот метод - обновлять его в соответствии с нашей схемой маршрутизации. Таким образом, вместо разделения returnUrl на части контроллера / действия я сохраняю returnUrl как есть и анализирую его, чтобы убедиться, что он содержит только относительный путь (например, /users/1), а не абсолютный путь (например, * 1045). *). Вот код, который я использую:

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

    return true;
}

Примечание: я знаю, что это открытое перенаправление может показаться не слишком важным делом по сравнению с XSS и CSRF, но мы, разработчики, единственное, что защищает наших клиентов от плохих парней - все, что мы можем сделать работу плохих парней труднее - победа в моей книге.

Спасибо, Брэд

Ответы [ 4 ]

9 голосов
/ 19 марта 2012

Джон Галлоуэй написал статью с решением для MVC 2 (и 1).

Вот фрагмент кода, который должен помочь с вашей проблемой:

SECURED (оригинальная статья обновлена ​​2014)

private bool IsLocalUrl(string url)
{
  return System.Web.WebPages.RequestExtensions.IsUrlLocalToHost(
      RequestContext.HttpContext.Request, url);
}
3 голосов
/ 26 мая 2010

Да, это уязвимость. Перед перенаправлением необходимо проверить строковый параметр returnUrl, передав его объекту Uri и убедитесь, что целевой домен совпадает с запрашивающим доменом. Также следует учитывать случай, когда returnUrl является относительным адресом, таким как /admin. Нет проблем в этом случае, так как перенаправление будет в то же приложение.

1 голос
/ 26 мая 2010

Вы всегда можете сохранить запись предыдущей страницы с помощью TempData, когда пользователь не аутентифицирован, и использовать ее для перенаправления на предыдущую страницу вместо параметра url.

0 голосов
/ 26 мая 2010

Пока вы используете один из вариантов Redirect, который использует параметры контроллера и действия или имя маршрута, вы должны быть в порядке, при условии, что у вас есть адекватные средства управления безопасностью для ваших методов контроллера.

Суть в том, что все, что вы используете для перенаправления, должно проходить через механизм маршрутизации и проверяться путем сопоставления маршрута.

Но я подозреваю, что настоящей уязвимостью является межсайтовый скриптинг. Если ваш злонамеренный пользователь не сможет внедрить какой-либо Javascript на страницу, он не сможет манипулировать возвращаемым URL-адресом или какими-либо его параметрами (поскольку вы иначе управляете всем кодом сервера и браузера).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...