Pytanie Jak unieważnić token OAuth po zmianie hasła?


Używamy ASP.NET Identity w projekcie Web Api z SimpleAuthorizationServerProviderużywamy tokenów OAuth do autoryzowania każdego żądania pochodzącego od klienta. (Tokeny mają i wygasają, nie używamy odświeżających tokenów.)

Kiedy użytkownicy zmieniają swoje hasło, chciałbym unieważnić tokeny, które mogą mieć, być może na innych urządzeniach. Czy istnieje sposób, aby to wyraźnie zrobić? Eksperymentowałem i zobaczyłem, że istniejące tokeny działają bez problemu po zmianie hasła, czemu należy zapobiec.

Pomyślałem o umieszczeniu hasła hash, lub części hasha w tokenie OAuth jako roszczenia i potwierdzeniu tego w OnAuthorization metoda naszego wyprowadzonego filtru AuthorizeAttribute.
Czy byłby to właściwy sposób rozwiązania problemu?


18
2017-11-06 09:52


pochodzenie


Czy nie jest częścią punktu z OAuth, że jest niezależny od zmian hasła? Dlaczego po prostu nie usunie tokena z serwera uwierzytelniającego, gdy zmieni hasło, a jeśli spróbuje użyć go na innych urządzeniach, to nie będzie działać. - DaImTo
"Dlaczego po prostu nie usunąć tokena z serwera uwierzytelniania": czy jest to możliwe dzięki tożsamości ASP.NET? Myślałem, że tokeny są samoistne, więc mogą być używane na dowolnej instancji serwera WWW, dlatego nie mamy serwera uwierzytelniania. - Mark Vincze
Jeśli to prawda, to brzmi jak potrzebuję odświeżenia w "ASP.NET Identity", to było trochę. Przepraszam. - DaImTo


Odpowiedzi:


Nie polecam umieszczania skrótu hasła jako roszczenia i uważam, że nie ma bezpośredniego sposobu na unieważnienie tokena po zmianie hasła.

Ale jeśli jesteś OK z trafieniem w DB z każdym żądaniem, wyślij je z aplikacji klienckiej do punktu końcowego chronionego interfejsu API, musisz zapisać token Identifier (Guid maybe) dla każdego tokena przyznanego właścicielowi zasobów, o który prosiłeś. Następnie przypisujesz token Identyfikator jako niestandardowe roszczenie do tego tokenu, po tym musisz sprawdzić tę tabelę dla każdego żądania, szukając identyfikatora tokena i nazwy użytkownika dla właściciela zasobu.

Po zmianie hasła usuwany jest ten rekord identyfikatora tokena dla tego właściciela zasobów (użytkownika), a przy następnym wysyłaniu tokena od klienta zostanie on odrzucony, ponieważ rekord dla tego tokenu i właściciela zasobów został usunięty.


12
2017-11-07 00:01



To było proste do wdrożenia i działa poprawnie. Dzięki! - Mark Vincze
Cieszę się, że to było pomocne. Jeśli chciałbyś, żebyś nie podzielił się częścią kodu, który utworzyłeś, aby to zaimplementować, jestem pewien, że będzie to przydatne dla innych :) - Taiseer Joudeh
Przesłałem pewne szczegóły kodu. - Mark Vincze
@TaiseerJoudeh W powyższym pytaniu załóżmy, że scenariusz jest taki sam, jednak zamiast zmieniać hasło użytkownik próbuje zalogować się na trzech różnych urządzeniach i chcę, aby tylko token działał, na którym Użytkownik ostatnio się zalogował, a dwa poprzednie tokeny pozostałych dwóch urządzeń powinny być odwołane / usunięte. Czy jest jakiś sposób, aby to osiągnąć? - Jyotish Singh


Oparłem swoje podejście na sugestii Taisera. Istota rozwiązania jest następująca. Za każdym razem, gdy użytkownik zmienia swoje hasło (i rejestruje), generowany jest nowy identyfikator GUID i zapisywany w bazie danych w tabeli użytkownika. Nazywam ten identyfikator GUID znaczek hasłai przechowuj go w obiekcie o nazwie LatestPasswordStamp.

Pieczęć ta musi zostać wysłana do klienta jako część tokena jako roszczenia. Można to osiągnąć za pomocą następującego kodu w GrantResourceOwnerCredentials metoda OAuthAuthorizationServerProvider-realizacja.

identity.AddClaim( new Claim( "PasswordTokenClaim", user.LatestPasswordStamp.ToString() ) );

Znaczek ten będzie wysyłany od klienta do serwera w każdym żądaniu i sprawdzane jest, czy znacznik nie został zmieniony w bazie danych. Jeśli tak, oznacza to, że użytkownik zmienił swoje hasło, prawdopodobnie z innego urządzenia. Weryfikacja odbywa się w naszym niestandardowym filtrze autoryzacji w ten sposób.

public class AuthorizeAndCheckStampAttribute : AuthorizeAttribute
{
    public override void OnAuthorization( HttpActionContext actionContext )
    {
        var claimsIdentity = actionContext.RequestContext.Principal.Identity as ClaimsIdentity;
        if( claimsIdentity == null )
        {
            this.HandleUnauthorizedRequest( actionContext );
        }

        // Check if the password has been changed. If it was, this token should be not accepted any more.
        // We generate a GUID stamp upon registration and every password change, and put it in every token issued.
        var passwordTokenClaim = claimsIdentity.Claims.FirstOrDefault( c => c.Type == "PasswordTokenClaim" );

        if( passwordTokenClaim == null )
        {
            // There was no stamp in the token.
            this.HandleUnauthorizedRequest( actionContext );
        }
        else
        {
            MyContext ctx = (MyContext)System.Web.Mvc.DependencyResolver.Current.GetService( typeof( MyContext ) );

            var userName = claimsIdentity.Claims.First( c => c.Type == ClaimTypes.Name ).Value;

            if( ctx.Users.First( u => u.UserName == userName ).LatestPasswordStamp.ToString() != passwordTokenClaim.Value )
            {
                // The stamp has been changed in the DB.
                this.HandleUnauthorizedRequest( actionContext );
            }
        }

        base.OnAuthorization( actionContext );
    }
}

W ten sposób klient otrzymuje błąd autoryzacji, jeśli próbuje autoryzować się za pomocą tokena, który został wydany przed zmianą hasła.


12
2017-11-18 20:52



Dobre rozwiązanie, czy nie ma oficjalnego sposobu, który OAuth sugeruje, że zajmujemy się takimi przypadkami? Chodzi mi o to, że wydaje się to być poważną dziurą w całym schemacie uwierzytelniania, jeśli wszystkie urządzenia mogą nadal uzyskiwać dostęp po zmianie hasła. - Zapnologica
Tak, myślę, że problem polega na tym, że OAuth sam nie wie nic o tym, skąd pochodzą dane tożsamości, to jest odpowiedzialność dostawcy tożsamości. Na przykład tutaj ASP.NET Identity i wbudowane funkcje obsługi OAuth są oddzielne i nie znają się nawzajem, dlatego musimy ręcznie powiadomić opiekuna o zmianie hasła. - Mark Vincze
Czy moje proponowane rozwiązanie będzie działało zgodnie z twoim doświadczeniem? stackoverflow.com/questions/29534111/... - Zapnologica
Dziękujemy za poświęcenie czasu na opublikowanie informacji o rozwiązaniu, które zadziałało dla Ciebie! - webworm
Prostszym rozwiązaniem na tej samej linii byłoby sprawdzenie daty wystawienia tokena na podstawie daty ostatniej zmiany hasła (przechowywanej w bazie danych). To zaoszczędziłoby konieczność generowania i przechowywania oraz przekazywania GUID. - paulH