У меня есть сайт MVC, который позволяет входить в систему как с помощью входа в формы, так и с помощью проверки подлинности Windows. Я использую собственный MembershipProvider, который аутентифицирует пользователей в Active Directory, класс System.Web.Helpers AntiForgery для защиты от CSRF и промежуточное ПО для проверки подлинности файлов cookie Owin.
Во время входа в систему, когда пользователь прошел аутентификацию в Active Directory, я делаю следующее:
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(StringConstants.ApplicationCookie);
var identity = new ClaimsIdentity(StringConstants.ApplicationCookie,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType);
if(HttpContext.Current.User.Identity is WindowsIdentity)
{
identity.AddClaims(((WindowsIdentity)HttpContext.Current.User.Identity).Claims);
}
else
{
identity.AddClaim(new Claim(ClaimTypes.Name, userData.Name));
}
identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Active Directory"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userData.userGuid));
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, identity);
Моя функция SignOut выглядит так:
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(StringConstants.ApplicationCookie);
Вход осуществляется через запрос jQuery.ajax. В случае успеха Window.location
обновляется до главной страницы сайта.
Вход с помощью Forms и IntegratedWindowsAuthentication
(IWA) работает, но я столкнулся с проблемой при входе в IWA. Вот что происходит:
- Пользователь выбирает IWA на странице входа и нажимает кнопку отправки. Это отправляется в обычное действие входа в систему через запрос ajax.
- Сайт получает запрос, видит опцию «использовать IWA» и перенаправляет на соответствующее действие. 302 ответ отправлен.
- Браузер автоматически обрабатывает ответ 302 и вызывает цель перенаправления.
- Фильтр видит, что запрос направлен на действие входа в IWA и что User.Identity.IsAuthenticated == false. Отправляется ответ 401.
- Браузер автоматически обрабатывает ответ 401. Если пользователь еще не прошел аутентификацию с помощью IWA в браузере, для этого появится всплывающее окно (поведение браузера по умолчанию). После получения учетных данных браузер выполняет тот же запрос с учетными данными пользователя.
- Сайт получает аутентифицированный запрос и олицетворяет пользователя, чтобы выполнить проверку Active Directory. Если пользователь проходит аутентификацию, мы завершаем SignIn, используя приведенный выше код.
- Пользователь перенаправляется на главную страницу сайта.
- Сайт получает запрос на загрузку главной страницы. Именно здесь вещи иногда идут наперекосяк.
User.Identity
в этот момент имеет типWindowsIdentity
сAuthenticationType
установленным наNegotiate
и НЕ как Я ожидаю, чтоClaimsIdentity
создан в методеSignIn
выше.
Сайт подготавливает главную страницу для пользователя, вызывая@AntiForgery.GetHtml()
в представлении. Это делается для создания нового токена AntiForgery с данными вошедшего в систему пользователя. Токен создается с помощьюWindowsIdentity
- Когда главная страница загружается, ajax-запросы к серверу приходят с
ClaimsIdentity
! Таким образом, первый поступивший запросPOST
неизбежно вызываетAntiForgeryException
, где отправленный им токен защиты от подделки предназначен «для другого пользователя».
Обновление страницы приводит к загрузке главной страницы с ClaimsIdentity
и разрешает выполнение POST
запросов.
Вторая проблема, связанная с этим: в любой момент после обновления, когда все предположительно работает нормально, запрос POST
может прийти с WindowsIdentity
, а не с ClaimsIdentity
, снова выдавая AntiForgeryException
.
- Это не какой-либо конкретный почтовый запрос,
- это нет через какое-то определенное время (может быть первый/второй запрос, может быть сотый),
- это необязательно, когда во время этого сеанса вызывается конкретный запрос на публикацию в первый раз.
Я чувствую, что либо что-то упускаю из виду в отношении User.Identity
, либо что-то сделал не так в процессе входа в систему... Есть идеи?
Примечание. Параметр AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
позволяет выполнить действие AntiForgery.Validate
независимо от того, получены ли WindowsIdentity
или ClaimsIdentity
, но, как указано в MSDN:
Будьте осторожны при установке этого значения. Неправильное использование может открыть уязвимости безопасности в приложении.
Без каких-либо дополнительных объяснений, я не знаю, какие уязвимости безопасности на самом деле открываются здесь, и поэтому мне не хочется использовать это в качестве решения.
HttpContext.Current.User.Identity.Claims
вообще без актерского состава. - person Scott Chamberlain   schedule 10.05.2018IIdentity
не имеет свойстваClaims
- person Guy Passy   schedule 13.05.2018