Projektuję usługę internetową zgodną z REST, do której muszą mieć dostęp użytkownicy, ale także inne usługi i aplikacje internetowe. Wszystkie przychodzące żądania muszą zostać uwierzytelnione. Cała komunikacja odbywa się za pośrednictwem protokołu HTTPS. Uwierzytelnianie użytkownika będzie działało w oparciu o token uwierzytelniający, uzyskany poprzez POST przesłanie nazwy użytkownika i hasła (przez połączenie SSL) do zasobu / session udostępnianego przez usługę.
W przypadku klientów usług internetowych za usługą klienta nie stoi żaden użytkownik końcowy . Żądania są inicjowane przez zaplanowane zadania, zdarzenia lub inne operacje komputerowe. Lista usług łączących jest znana z góry (oczywiście, tak mi się wydaje). Jak mam uwierzytelnić te żądania pochodzące z innych usług (internetowych)? Chcę, aby proces uwierzytelniania był jak najłatwiejszy do wdrożenia dla tych usług, ale nie kosztem bezpieczeństwa. Jaki byłby standard i najlepsze praktyki w takim scenariuszu?
Opcje, które przychodzą mi do głowy (lub zostały mi zasugerowane):
Niech usługi klienckie używają „fałszywej” nazwy użytkownika i hasła i uwierzytelniają je w taki sam sposób, jak użytkowników. Nie podoba mi się ta opcja - po prostu nie czuję się dobrze.
Przypisz stały identyfikator aplikacji dla usługi klienta, być może także klucz aplikacji. O ile zrozumiałem, jest to to samo, co posiadanie nazwy użytkownika i hasła. Za pomocą tego identyfikatora i klucza mogę uwierzytelnić każde żądanie lub utworzyć token uwierzytelniający do uwierzytelniania kolejnych żądań. Tak czy inaczej, nie podoba mi się ta opcja, ponieważ każdy, kto może zdobyć identyfikator aplikacji i klucz, może podszyć się pod klienta.
Mógłbym dodać sprawdzenie adresu IP do poprzedniej opcji. Utrudniłoby to wykonywanie fałszywych żądań.
Certyfikaty klienta. Skonfiguruj własny urząd certyfikacji, utwórz certyfikat główny i utwórz certyfikaty klienta dla usług klienckich. Przychodzi jednak na myśl kilka kwestii: a) w jaki sposób mogę nadal zezwalać użytkownikom na uwierzytelnianie bez certyfikatów oraz b) jak skomplikowany jest ten scenariusz do wdrożenia z punktu widzenia obsługi klienta?
Coś jeszcze - muszą tam być inne rozwiązania?
Moja usługa działałaby w Javie, ale celowo pominąłem informacje o tym, na jakim konkretnym frameworku będzie zbudowana, ponieważ bardziej interesują mnie podstawowe zasady, a nie szczegóły implementacji - zakładam, że najlepsze rozwiązanie będzie być możliwe do wdrożenia niezależnie od podstawowej struktury. Jednak jestem trochę niedoświadczony w tym temacie, więc konkretne wskazówki i przykłady dotyczące rzeczywistego wdrożenia (takie jak przydatne biblioteki stron trzecich, artykuły itp.) Będą również bardzo mile widziane.
Odpowiedzi:
Każde rozwiązanie tego problemu sprowadza się do wspólnego sekretu. Nie podoba mi się również zakodowana nazwa użytkownika i opcja hasła, ale ma tę zaletę, że jest dość prosta. Certyfikat klienta też jest dobry, ale czy naprawdę różni się znacznie? Na serwerze znajduje się certyfikat, a na kliencie. Jego główną zaletą jest to, że trudniej jest brutalna siła. Miejmy nadzieję, że masz inne zabezpieczenia, które chronią przed tym.
Nie sądzę, aby Twój punkt A dotyczący rozwiązania z certyfikatem klienta był trudny do rozwiązania. Po prostu używasz gałęzi.
if (client side certificat) { check it } else { http basic auth }
Nie jestem ekspertem w dziedzinie java i nigdy nie pracowałem z nim przy tworzeniu certyfikatów po stronie klienta. Jednak szybkie Google prowadzi nas do tego samouczka, który wygląda prosto w Twoją uliczkę.Pomimo całej tej dyskusji na temat „tego, co najlepsze”, pozwólcie mi tylko zaznaczyć, że istnieje inna filozofia, która mówi, że „mniej kodu, mniej sprytu, tym lepiej”. (Osobiście trzymam się tej filozofii). Rozwiązanie dotyczące certyfikatu klienta brzmi jak dużo kodu.
Wiem, że zadałeś pytania na temat OAuth, ale propozycja OAuth2 zawiera rozwiązanie Twojego problemu o nazwie „ tokeny okaziciela ”, które muszą być używane w połączeniu z SSL. Myślę, że ze względu na prostotę wybrałbym albo zakodowanego na stałe użytkownika / przepustkę (po jednym na aplikację, aby można je było odwołać indywidualnie) lub bardzo podobne tokeny okaziciela.
źródło
Po przeczytaniu twojego pytania powiedziałbym, że wygeneruj specjalny token, aby wykonać wymagane żądanie. Ten token będzie żył w określonym czasie (powiedzmy za jeden dzień).
Oto przykład z do generowania tokena uwierzytelniania:
na przykład: 3 czerwca 2011 r
następnie połącz z hasłem użytkownika, na przykład „my4wesomeP4ssword!”
Następnie wykonaj MD5 tego ciągu:
Kiedy dzwonisz do żądania, zawsze używaj tego tokena,
Ten token jest zawsze wyjątkowy każdego dnia, więc myślę, że ten rodzaj ochrony jest więcej niż wystarczający, aby zawsze chronić naszą usługę.
Nadzieja pomaga
:)
źródło
Istnieje kilka różnych podejść.
Puryści RESTful będą chcieli, abyś używał uwierzytelniania BASIC i wysyłał dane uwierzytelniające przy każdym żądaniu. Ich uzasadnieniem jest to, że nikt nie przechowuje żadnego państwa.
Usługa klienta może przechowywać plik cookie, który przechowuje identyfikator sesji. Osobiście nie uważam tego za tak obraźliwe, jak niektórzy purystowie, od których słyszę - wielokrotne uwierzytelnianie może być kosztowne. Wygląda jednak na to, że nie przepadasz za tym pomysłem.
Z twojego opisu naprawdę wygląda na to, że możesz być zainteresowany OAuth2. Moje dotychczasowe doświadczenia, z tego, co widziałem, są takie, że jest to trochę zagmatwane i trochę krwawiące. Istnieją implementacje, ale jest ich niewiele. W Javie rozumiem, że został on zintegrowany z modułami bezpieczeństwa Spring3 . (Ich samouczek jest ładnie napisany.) Czekałem, aby zobaczyć, czy będzie rozszerzenie w Restlet , ale jak dotąd, chociaż zostało zaproponowane i może znajdować się w inkubatorze, nadal nie zostało w pełni włączone.
źródło
Wierzę w podejście:
jest dość standardowe, niezależnie od sposobu wdrożenia i innych szczegółowych szczegółów technicznych.
Jeśli naprawdę chcesz pchnąć kopertę, być może możesz uznać, że klucz https klienta jest tymczasowo nieprawidłowy do momentu zweryfikowania poświadczeń, ograniczyć informacje, jeśli nigdy nie są, i przyznać dostęp po ich weryfikacji, ponownie w oparciu o wygaśnięcie.
Mam nadzieję że to pomoże
źródło
Jeśli chodzi o podejście do certyfikatu klienta, nie byłoby to strasznie trudne do wdrożenia, a jednocześnie pozwoliłoby użytkownikom bez certyfikatów klienta w formacie.
Gdybyś faktycznie utworzył własny urząd certyfikacji z podpisem własnym i wystawił certyfikaty klienta dla każdej usługi klienta, miałbyś łatwy sposób uwierzytelnienia tych usług.
W zależności od używanego serwera WWW powinna istnieć metoda określania uwierzytelniania klienta, która będzie akceptować certyfikat klienta, ale go nie wymaga. Na przykład w Tomcat podczas określania łącznika https można ustawić „clientAuth = want” zamiast „true” lub „false”. Następnie upewnij się, że dodałeś samopodpisany certyfikat CA do swojego magazynu zaufanych certyfikatów (domyślnie plik cacerts w używanym środowisku JRE, chyba że określono inny plik w konfiguracji serwera internetowego), więc jedynymi zaufanymi certyfikatami byłyby te wydane poza urząd certyfikacji z podpisem własnym.
Po stronie serwera pozwolisz na dostęp do usług, które chcesz chronić, tylko wtedy, gdy będziesz w stanie pobrać certyfikat klienta z żądania (nie zerowy) i pomyślnie przejdziesz testy DN, jeśli wolisz dodatkowe zabezpieczenia. Użytkownicy bez certyfikatów klienta nadal będą mogli uzyskiwać dostęp do usług, ale po prostu nie będą mieli żadnych certyfikatów w żądaniu.
Moim zdaniem jest to najbardziej „bezpieczny” sposób, ale z pewnością ma swoją krzywą uczenia się i narzut, więc niekoniecznie musi być najlepszym rozwiązaniem dla Twoich potrzeb.
źródło
5. Coś jeszcze - muszą być inne rozwiązania?
Masz rację, jest! I nazywa się JWT (JSON Web Tokens).
JSON Web Token (JWT) to otwarty standard (RFC 7519), który definiuje kompaktowy i niezależny sposób bezpiecznego przesyłania informacji między stronami w postaci obiektu JSON. Te informacje można zweryfikować i zaufać, ponieważ są podpisane cyfrowo. Tokeny JWT można podpisywać za pomocą klucza tajnego (za pomocą algorytmu HMAC) lub pary kluczy publiczny / prywatny za pomocą RSA.
Gorąco polecam zajrzenie do JWT. Są znacznie prostszym rozwiązaniem problemu w porównaniu z rozwiązaniami alternatywnymi.
https://jwt.io/introduction/
źródło
Możesz utworzyć sesję na serwerze i udostępniać ją
sessionId
między klientem a serwerem przy każdym wywołaniu REST.Po pierwsze żądanie uwierzytelnienia REST:
/authenticate
. Zwraca odpowiedź (zgodnie z formatem klienta) zsessionId: ABCDXXXXXXXXXXXXXX
;Zapisz to
sessionId
wMap
aktualnej sesji.Map.put(sessionid, session)
lub używaćSessionListener
do tworzenia i niszczenia kluczy dla Ciebie;Uzyskaj identyfikator sesji przy każdym wywołaniu REST, na przykład
URL?jsessionid=ABCDXXXXXXXXXXXXXX
(lub w inny sposób);HttpSession
z mapy za pomocąsessionId
;źródło
Użyłbym aplikacji przekierowującej użytkownika do Twojej witryny z parametrem identyfikatora aplikacji, gdy użytkownik zatwierdzi żądanie, wygeneruje unikalny token, który jest używany przez inną aplikację do uwierzytelniania. W ten sposób inne aplikacje nie obsługują poświadczeń użytkownika, a użytkownicy mogą dodawać, usuwać i zarządzać innymi aplikacjami. Foursquare i kilka innych witryn uwierzytelnia się w ten sposób i jest bardzo łatwy do wdrożenia jako inna aplikacja.
źródło
Oprócz uwierzytelniania sugeruję, abyś pomyślał o szerszej perspektywie. Zastanów się, czy Twoja usługa zaplecza REST zgodna z REST bez żadnego uwierzytelniania; następnie umieść bardzo prostą usługę warstwy pośredniej wymagającą uwierzytelnienia między użytkownikiem końcowym a usługą backendu.
źródło