Jak powinno wyglądać logowanie przez REST Api z 2FA i tokenem JWT?

0

Hej, tak jak w tytule - jak powinna wyglądać rejestracja użytkownika i dwuetapowe logowanie na podstawie tych danych? Spróbuję opisać tak jak ja to widzę i byłbym wdzięczny gdyby ktoś wytknął mi błędy, wskazał lepsze rozwiązanie.

  1. Udostępniam endpoint /api-v1/register:
  • który przyjmuje RegistrationRequestDto na który składają się:
  private final String username;
  private final String email;
  private final String password;
  private final String phone;
 private final boolean is2FaEnabled;
  • Już w tym miejscu waliduję poprawność tych danych za pomocą adnotacji z pakietu javax.validation.
  • Ewentualne podwójne podawanie jakiś pól (np. String password, String passwordConfirmation) żeby uniknąć wysłanie requesty z błędnym hasłem/ emailem odpuszczam bo zakładam, że jeżeli ktoś rejestruje się przez Api to wie co robi, coś takiego można sprawdzić na froncie gdyby takowy miał istnieć.
  • Requestów do tego endpointu nie filtruję, nie robi mi różnicy czy np klient który próbuje się rejestrować ma już token świadczący o tym, że jest użytkownikiem itp.
  • Potem requesta wrzucam w jakiś serwis który sprawdza czy taki username/email/phoneNumber nie istnieją już w bazie, zapisuje Usera w bazie z jakąś flagą, że nie jest jeszcze aktywny. Generuje jednorazowy token który także zapisuje do bazy i paruje z encją usera. Asynchronicznie wysyłam SMSa z tym tokenem pod zapisany w bazie numer.
  • Jako odpowiedź gdyby się powiodło zwracam informacje o zapisanym userze (email, czas o której został zapisany do bazy itd itd) w body + status, w razie niepowodzenia treść wyjątku w body + status.
  • Teraz w kwestii usera jest potwierdzenie rejestracji za pomocą nasępnego endpointu.
  1. Udostępniam endpoint /api-v1/register?token={token}
  • Znowu nie interesuje mnie filtrowanie, bez różnicy kto próbuje wysłać request.
  • Pobieram ze ścieżki token, przekazuje do serwisu, wyszukuje go w bazie i sprawdzam czy taki token istnieje - jeżeli tak to zmieniam userowi status na aktywny, status tokena na aktywny.
  • Jako odpowiedź zwracam sam status w razie powodzenia lub status + treść wyjątku w body w razie niepowodzenia.
  1. To tyle jeżeli chodzi o rejestracje użytkownika - mam w bazie użytkownika z potwierdzonym numerem telefonu i informacją czy logowanie ma potwierdzać kodem z SMS, jeżeli chodzi o logowanie to zrobię je dokładnie jak tutaj: https://stackoverflow.com/questions/41814194/how-to-design-a-stateless-rest-login-with-2-factor-authentication-2fa tylko sprawdzę przy próbie logowania user ma is2FaEnabled i sposób logowania 2Fa (to na potrzeby gdyby miały dojść nowe sposoby na drugi etap.

Aha, i pytanie - gdybym miał więcej sposobów na potwierdzenie logowania poza kodem SMS to jak powinien wyglądać mój RegistrationRequestDto?

0
  1. Przy rejestracji nie dodaje sie 2fa poniewaz uzytkownik wlacza 2fa dopiero po logowaniu, a po samej rejestracji powinien dopiero odebrac maila wiec ta dana nie jest prawidlowa w tym miejscu.
  2. Jeżeli robisz jedno hasło to lepiej odpuśc to pole i generuj hasło i wysylaj uzytkownikowi albo dodaj pole confirm password.
  3. "że jeżeli ktoś rejestruje się przez Api to wie co robi," nie rozumiem tego stwierdzenia, przez api rozmawiaja dwie aplikacje a nie uzytkownik wiec co ma do rzeczy przez co sie loguje ? on nawet nie wie przez co, wiesz w ogole do czego sluzy API ? chcesz walidacje na froncie robic xDDDD ? hahahah miszcz
  4. "Requestów do tego endpointu nie filtruję" - to błąd, juz na tym etapie powinienes filtrowac typy czy to POST, DELETE, PUT, GET, FILE itd oraz filtrować IP zeby tylko np dane zatwierdzone aplikacje lub karje sie laczyly. Wykrywac brute forcy czy ddosy. jezeli user nie ma tokena to po co rzucac zapytanie do kontrolera zeby go tylko zapychac i spowalniac operacje dla juz zalogowanych klientow. Lipa panie.
  5. Zapisujesz usera do bazy, ok. ale po co generujesz token ? przeciez nie jest on do niczego potrzebny. I po co chcesz wysylac jakiegos tokena sms ? do czego ? skad wiesz ze user podal prawidlowy numer? najpierw niech sie zarejestruje a potem niech dodaje numery telefonow ktore potwierdzi tokenem
  6. informacje mozesz zwrocic w formie register success lub failed i status czemu
  7. rejestracjer user potweirdza klikajac na link w mailu

Powinno to wygladac tak ze dajesz username, email lub username, email, haslo i potw hasla
po rejestracji wysylasz ze system ma wyslac maila i to wstawiasz do kolejki z mailami - bo chyba nie bedziesz wysylal majla w funkcji RegistrationRequestDto
uzytkownik odbiera email i po aktywacji konta moze sie logowac.
tam juz ustawia 2fa i numery telefonow

p.s. kardynalny blad twoj to "że jeżeli ktoś rejestruje się przez Api to wie co robi," jezeli zakladasz ze uzytkownik cokolwiek wie i bedzie robil to przy twojej aplikacji to jestes skazany na porazke

1

hahahah miszcz
Pofolguj. Autor pisał o czymś w rodzaju "Potwierdź hasło " co ma sens przy wpisywaniu hasła z palca na froncie w formularzu. Na backendzie bym tego nie walidował. Więc tak, w tym kontekście jak ktoś używa api to wie jakie chce hasło, wie co robi.

0

@chomikowski

"Requestów do tego endpointu nie filtruję" - to błąd, juz na tym etapie powinienes filtrowac typy czy to POST, DELETE, PUT, GET, FILE itd oraz filtrować IP zeby tylko np dane zatwierdzone aplikacje lub karje sie laczyly. Wykrywac brute forcy czy ddosy. jezeli user nie ma tokena to po co rzucac zapytanie do kontrolera zeby go tylko zapychac i spowalniac operacje dla juz zalogowanych klientow. Lipa panie.

Miałem na myśli filtrowanie requestów żeby sprawdzić czy user ma już token albo jakieś informacji nt logowania w nagłówku itp bo z mojego punktu widzenia to chyba bez różnicy czy zarejestrować się próbuje zupełnie nowy użytkownik czy ktoś kto dostał już poprawny token albo jest w trakcie logowania. A może powinienem udostępnić endpoint /logout który usuwa token i nagłówki, do /register dopuszczać tylko requesty bez tokena i w przypadku ponownej rejestracji usera który jest już zalogowany musiałby on:

  1. wykonać request pod /logout żeby pozbyć się tokena
  2. dopiero wtedy bez tokena zgłosić się pod /register

ale to chyba przekombinowane, idk.

Zapisujesz usera do bazy, ok. ale po co generujesz token ? przeciez nie jest on do niczego potrzebny. I po co chcesz wysylac jakiegos tokena sms ? do czego ? skad wiesz ze user podal prawidlowy numer? najpierw niech sie zarejestruje a potem niech dodaje numery telefonow ktore potwierdzi tokenem

Token generuje właśnie po to żeby wymusić na użytkowniku przepisanie go w celu potwierdzenia numeru telefonu a co za tym idzie rejestracji - jeżeli to zrobi to ok, posiada ten numer i faktycznie mogę ustawić jego konto jako zarejestrowane do końca. Jeżeli nie to ok - najwyżej usunę ten wpis po 24 albo 48h cronem

rejestracjer user potweirdza klikajac na link w mailu

Zaproponowałeś identyczne rozwiązanie co przy sms

1

Czyli chcesz oprzec rejestracje o nr telefonu.

  1. pobierz dane od uzytkownika: nazwa, email, haslo, potw hasla,
    PROBLEM 1:
    nr telefonu - polski ? zaagraniczny tez ? a jak nie mam numeru albo nie chce podawac to juz sie nie zareejstruje tak ?

  2. Użytkownik podaje wszystkie dane, zapisujesz je do bazy do tabeli users.

  3. tabela verify przechowuje tokeny wiec generujesz token 6 znakow dodajesz go do tabeli z flaga aktywny i wysylasz sms

OPCJA 1 - wszystko ok
4. użytkownik dostaje token przez sms i wpisuje go do formularza
5. system sprawdza w bazie z tokenami gdzie wybiera po tokenie i fladze aktywny, jesli jest to aktywuje usera i oznacza token jako nieaktywny

OPCJA 2 - uzytkownik zamknal niechcacy strone z rejestracja przy oczekiwaniu na token z smsa
4. uzytkownik dostal token ale nie ma go gdzie wpisac
5. dokonuje ponownej rejestracji na te sae dane
6. system patrzy ze taki uzytkownik nie jest aktywny
7. sprawdza czy taki uzytkownik ma token z flaga aktywny jesli nie ma to generujesz mu token i wysyla
8. jesli ma token z flaga aktywny to pobieram token i wysylam go ponownie do usera

PROBELM 2:

  1. uzytkownik podal dane i oczekuej na token ale jeszcze go nie wpisał i zmienil zdanie lub podal wtedy bledny numer telefonu a teraz chce jeszcze raz sie zarejestrowac podajac dobry nr telefonu
  2. system wpisze go jako nowego usera ? czy podmieni numer telefonu ? czy powie ze juz taki user istnieje i wyslal mu smsy na tamten numer stary co sie pomylil w cyferce ? Juz na etapie rejestracji user ma dzwonic i angazowac twoj support do rozwiazania problemu ?

PROBLEM 3 :

  1. napisze skrypt rejestrujacy usera zeby ci wywalic wszystkie smsy z pakietu i bede podawal losowe numery telefonow

p.s.

  1. wykonać request pod /logout żeby pozbyć się tokena
  2. dopiero wtedy bez tokena zgłosić się pod /register

Nie myl rejestracji z logowaniem, nie mozesz wywolac logout na kimś kto sie nigdy jeszcze nie zdazyl zarejestrowac. Mylisz pojecia, kod do potwerdzenia numeru z smsa ktory nieszczesnie nazwales token to nie ten am TOKEN ktory sluzy do identyfikacji i logowania usera.

0

Ja bym to zrobił tak:

  • rejestracja bez aktywacji MFA, username, password, email. Ważne, żeby przewidzieć sytuację "co jeżeli email nie dojdzie", czyli ponowne wysłanie na te same dane
  • jeżeli aplikacja wymaga MFA, to pozwalasz użytkownikowi zalogować się tylko po to, żeby aktywować MFA - ustaw od razu enum/set zamiast booleana. Co jak będzie chciał mieć dodatkowo np. google authenticator, email, wiadomość głosową czy jakieś inne cuda?
  • użytkownik loguje się hasłem, aktywuje wymaganą/wybraną liczbę dodatkowych metod, logout
  • użytkownik loguje się ponownie, podaje hasło + coś tam jeszcze, dostaje JWT z określeniem kim jest i jakie są jego prawa, lub jakich metod użył do uwierzytelnienia, jeżeli jest tam coś więcej, to dostaje prawa do zabawy innymi endpointami niż aktywacja MFA.

1 użytkowników online, w tym zalogowanych: 0, gości: 1