Как отследить просроченные WIF-файлы cookie?
У меня есть интересная проблема с попыткой отследить истекшие сеансы аутентификации WIF / куки.
В качестве предыстории: сайт MVC 3, использует Windows Identity Foundation (WIF), который имеет доверие к серверу ADFS в качестве STS. Весь сайт защищен SSL. STS имеет срок действия токена 60 минут.
Когда пользователь выходит из системы вручную, мы просто вызываем метод SignOut в модуле FedAuth:
FederatedAuthentication.WSFederationAuthenticationModule.SignOut(false);
Это, конечно, удаляет файлы cookie FedAuth, но здесь начинается проблема. Если я получу эти файлы cookie с помощью Fiddler, я смогу повторно представить их на сайте в течение срока их действия и по-прежнему рассматриваться как вошедшие в систему.
Я понимаю, что это выполняется с привилегированной позиции браузера, принявшего fiddler в качестве прокси-сервера... но клиент обеспокоен тем, что эти файлы cookie, срок действия которых на самом деле не истек, представляют значительную угрозу безопасности. Они не уверены, что SSL в достаточной степени защищает сайт, и что если злоумышленник может выполнить атаку MITM, он может использовать эти файлы cookie после того, как пользователь решит, что он вышел из системы.
Я объяснил, что если они уязвимы после выхода из системы, они уязвимы во время входа, но им все равно...
Поэтому я искал способы быть уверенным, что после того, как пользователь выйдет из системы, cookie-файлы fedauth, связанные с этим сеансом входа, будут считаться просроченными. В обработчиках WIF, похоже, нет встроенного механизма для отслеживания просроченных токенов, и я не нашел ничего другого, связанного с этим.
Я предполагаю, что это на самом деле более широкая проблема -> как вообще определить просроченные куки? Действительный файл cookie - это действительный файл cookie!
Очевидное решение состоит в том, чтобы как-то отслеживать эти куки-файлы после выхода из системы, но я бы хотел, если возможно, избегать маршрута с собственным кодом; как новичок, много литературы по безопасности говорит, что следует избегать пользовательского кодирования любого вида сессионной механики, поскольку вы, вероятно, ошибетесь!
Кто-нибудь знает какие-либо стандартные решения в ASP.NET для этой проблемы?
Заранее спасибо.
2 ответа
Вы не можете без серверного списка недавно отозванных токенов. Вот почему обычно мы полагаемся на врожденное истечение срока действия, а также HTTPS для предотвращения утечки / кражи токена.
Мне была поручена аналогичная просьба нашей службы безопасности. Я решил сохранить идентификатор сеанса asp.net в файле cookie OWIN, и при каждом запросе, который содержал идентификатор сеанса в файле cookie, я проверяю, что он совпадает с идентификатором активного сеанса.
Сохраните идентификатор сеанса в файле cookie ( адаптированный из этого ответа) в конце первого запроса, который аутентифицирован и у которого еще нет идентификатора сеанса в файле cookie:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
bool authenticated = User.Identity.IsAuthenticated;
var sessionGuid = (User as ClaimsPrincipal).FindFirst("sessionID")?.Value;
//put the SessionID into the cookie.
if (authenticated && string.IsNullOrEmpty(sessionGuid))
{
var id= Session.SessionID;
//update the guid claim to track with the session
var authenticationManager = HttpContext.GetOwinContext().Authentication;
// create a new identity from the old one
var identity = new ClaimsIdentity(User.Identity);
// update claim value
identity.RemoveClaim(identity.FindFirst("sessionID"));
identity.AddClaim(new Claim("sessionID", id));
// tell the authentication manager to use this new identity
authenticationManager.AuthenticationResponseGrant =
new AuthenticationResponseGrant(
new ClaimsPrincipal(identity),
new AuthenticationProperties { IsPersistent = true }
);
}
}
Затем по каждому будущему запросу, если я найду сеанс в куки, сравните его с активным сеансом. Если они не совпадают, выйдите из системы:
protected override void OnActionExecuting( ActionExecutingContext filterContext)
{
var claim = (User as ClaimsPrincipal).FindFirst("sessionID")?.Value;
//does the owin cookie have a sessionID?
if (!string.IsNullOrEmpty(claim))
{
string session = Session.SessionID;
//does it match the one stored in the session?
if(session != claim)
{
//no? log the user out again..
Session.Abandon();
//redirect to logged out page
this.Request.GetOwinContext().Authentication.SignOut();
//tell them its over..
Response.Write("Expired Session");
Response.End();
}
}
base.OnActionExecuting(filterContext);
}