Tworzenie interfejsu API dla aplikacji mobilnych - Uwierzytelnianie i autoryzacja

189

Przegląd

Chcę utworzyć interfejs API (REST) ​​dla mojej aplikacji. Początkowym / głównym celem będzie konsumpcja przez aplikacje mobilne (iPhone, Android, Symbian itp.). Badałem różne mechanizmy uwierzytelniania i autoryzacji internetowych interfejsów API (badając inne implementacje). Mam głowę wokół większości podstawowych koncepcji, ale wciąż szukam wskazówek w kilku obszarach. Ostatnią rzeczą, którą chcę zrobić, jest wynalezienie koła, ale nie znajduję żadnych standardowych rozwiązań, które pasowałyby do moich kryteriów (jednak moje kryteria mogą być błędne, więc nie krępuj się również krytykować). Ponadto chcę, aby interfejs API był taki sam dla wszystkich platform / aplikacji, które go wykorzystują.

oAuth

Przejdę dalej i wyrzucę swój sprzeciw wobec oAuth, ponieważ wiem, że prawdopodobnie będzie to pierwsze oferowane rozwiązanie. W przypadku aplikacji mobilnych (a dokładniej aplikacji niebędących aplikacjami internetowymi) opuszczanie aplikacji (aby przejść do przeglądarki internetowej) w celu uwierzytelnienia wydaje się niewłaściwe. Ponadto, nie ma (jestem tego świadom) sposobu, aby przeglądarka zwróciła wywołanie zwrotne do aplikacji (szczególnie na wielu platformach). Znam kilka aplikacji, które to robią, ale po prostu źle się czuję i daje przerwę w UX aplikacji.

Wymagania

  1. Użytkownik wprowadza nazwę użytkownika / hasło do aplikacji.
  2. Każde wywołanie interfejsu API jest identyfikowane przez aplikację wywołującą.
  3. Koszty ogólne są ograniczone do minimum, a aspekt autoryzacji jest intuicyjny dla programistów.
  4. Mechanizm jest bezpieczny zarówno dla użytkownika końcowego (dane logowania nie są ujawnione), jak i programisty (dane logowania aplikacji nie są ujawnione).
  5. Jeśli to możliwe, nie wymagaj https (w żadnym wypadku nie jest to trudne wymaganie).

Moje obecne przemyślenia na temat wdrażania

Zewnętrzny programista poprosi o konto API. Otrzymają apikey i apisecret. Każde żądanie wymaga co najmniej trzech parametrów.

  • apikey - podany deweloperowi przy rejestracji
  • timestamp - podwaja się jako unikalny identyfikator każdej wiadomości dla danego apikey
  • hash - skrót mieszania znacznika czasu + apisecret

Apikey jest wymagany do zidentyfikowania aplikacji wydającej żądanie. Znacznik czasu działa podobnie do oauth_nonce i unika / łagodzi ataki powtórki. Hash zapewnia, że ​​żądanie zostało faktycznie wydane przez właściciela danego apikey.

W przypadku żądań uwierzytelnionych (wykonanych w imieniu użytkownika) nadal nie jestem zdecydowany, czy pójść z trasą tokenu dostępu lub kombinacją nazwy użytkownika i hasła. Tak czy inaczej, w pewnym momencie wymagane będzie połączenie nazwy użytkownika / hasła. Kiedy tak się stanie, zostanie użyty skrót kilku informacji (apikey, apisecret, timestamp) + hasło. Chciałbym poznać opinie na ten temat. Do Twojej wiadomości, najpierw musieliby hashować hasło, ponieważ nie przechowuję haseł w moim systemie bez mieszania.

Wniosek

Do Twojej wiadomości, nie jest to prośba o to, jak zbudować / ustrukturyzować API w ogóle, tylko jak obsługiwać uwierzytelnianie i autoryzację wyłącznie z poziomu aplikacji.

Losowe przemyślenia / pytania bonusowe

W przypadku interfejsów API, które wymagają tylko apikey jako części żądania, w jaki sposób można uniemożliwić komuś innemu niż właściciel apikey zobaczenie apikey (od momentu wysłania go w postaci jawnej) i wysyłanie nadmiernych próśb o przekroczenie limitów użycia? Może po prostu zastanawiam się nad tym, ale czy nie powinno być czegoś, co mogłoby potwierdzić, że prośba została zweryfikowana przez apikey właściciela? W moim przypadku taki był apisecret, nigdy nie jest pokazywany / przesyłany bez mieszania.

Mówiąc o hashach, co powiesz na md5 vs hmac-sha1? Czy to naprawdę ma znaczenie, gdy wszystkie wartości są mieszane z wystarczająco długimi danymi (np. Apisecret)?

Wcześniej zastanawiałem się nad dodaniem soli na użytkownika / wiersz do skrótu hasła moich użytkowników. Gdybym miał to zrobić, w jaki sposób aplikacja mogłaby utworzyć pasujący skrót, nie znając użytej soli?

jsuggs
źródło
1
Miałem nadzieję, że otrzymam jeszcze kilka komentarzy / sugestii. Czy pytanie jest zbyt niejasne / dwuznaczne?
jsuggs
6
pytanie jest idealne, ale nawet prawie 2 lata później, oauth implementacje wydają się tajemnicze ... mam trudności z osiągnięciem dokładnie tego, o czym mówiłeś powyżej. mam dodatkowy wymiar: nie chcę używać pary loginName / Password - chcę użyć weryfikacji tożsamości Google na Androidzie / iOS (Symbian został uznany przez WWF za „prawie wymarły gatunek”) i odmawiam rozwoju dla Windows Mobile (jak to obecnie nazywają).
Tony Gil
8
to niedorzeczne, że tak jak wszyscy sugerują oauth 2.0, jeszcze nie znalazłem jasnego, prostego samouczka lub przykładu, który używa wspólnego angielskiego, aby wyjaśnić kroki, wymagania, czynności do wykonania i nie itd.
ChuckKelly
2
Przeczytaj ten konkretny przepływ OAuth2.0 (przepływ hasła właściciela zasobów). Brak przekierowań na stronę internetową. techblog.hybris.com/2012/06/11/…
Franklin
1
Szukam również tej samej odpowiedzi. Znalazłem dobry artykuł, który został niedawno napisany. Mam nadzieję, że to pomoże. stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
Nowy w Rails

Odpowiedzi:

44

Sposób, w jaki myślę o logowaniu się w moich projektach, to:

  1. przed zalogowaniem użytkownik żąda login_tokenod serwera. Są one generowane i przechowywane na serwerze na żądanie i prawdopodobnie mają ograniczony okres użytkowania.

  2. aby się zalogować, aplikacja oblicza skrót hasła użytkownika, następnie haszy hasło hasłem, login_tokenaby uzyskać wartość, a następnie zwraca zarówno login_tokenskrót, jak i skrót.

  3. Serwer sprawdza login_token, czy został wygenerowany, usuwając go z listy prawidłowych login_tokenadresów. Serwer następnie łączy swój zapisany skrót hasła użytkownika z login_tokeni zapewnia, że ​​pasuje on do przesłanego połączonego tokena. Jeśli jest zgodny, uwierzytelniłeś użytkownika.

Zaletą tego jest to, że nigdy nie przechowujesz hasła użytkownika na serwerze, hasło nigdy nie jest przekazywane jawnie, hash hasła jest przekazywany tylko podczas tworzenia konta (chociaż mogą istnieć sposoby na obejście tego), i powinno być bezpieczne przed atakami powtórkowymi, ponieważ login_tokensą usuwane z bazy danych przy użyciu.

Michael Anderson
źródło
Dzięki, zapomniałem dodać część o haszowaniu hasła po stronie aplikacji. Nie przechowuję haseł użytkowników w czytelny sposób (hash przed przechowywaniem).
jsuggs,
2
Widzę wadę tej metody: nie możesz przechowywać solonych haseł w DB. Jeśli atakujący położyli ręce na twoją bazę danych, nie będą musieli dokonywać żadnego odszyfrowywania. Ponieważ skrót hasłowy to prawdziwe hasło w tym schemacie.
sigod
2
@sigod Masz rację. Chociaż myślę, że istnieje fundamentalna dychotomia - albo musisz zaufać swojemu transportowi, albo zaufać swojemu magazynowi. Systemy logowania korzystające z haseł solonych ufają warstwie transportowej - w ten sposób przekazują hasło od użytkownika do systemu uwierzytelniania w sposób wyraźny. Ten przypadek nie ufa warstwie transportowej (myślę, że było tak, ponieważ platforma, na którą celowałem, miała złe wsparcie dla SHTTP). Jeśli ufasz warstwie transportowej, możesz być w stanie dokonać innych kompromisów.
Michael Anderson,
Mam 3 problemy: 1) w jaki sposób hasło użytkownika nigdy nie jest przechowywane na serwerze? w kroku 2 wspomniałeś, że przechowuje zaszyfrowane hasło użytkownika. 2) Hasło użytkownika nigdy nie jest przekazywane jawnie. Ale tak naprawdę jest on haszowany na kliencie, a następnie porównywany z haszowanym hasłem na serwerze, co jest prawie identyczne z przekazywaniem i przechowywaniem go w czystości, jaki jest sens tego? 3) Ta metoda zakłada, że ​​osoba atakująca nie wie, jak hash login_token + hasło, co narusza zasadę Kerckhoffa i powoduje, że jest naprawdę niepewna.
Tamer Shlash
14

To mnóstwo pytań w jednym, myślę, że sporo osób nie udało się przeczytać do końca :)

Moje doświadczenie z uwierzytelnianiem usług sieciowych polega na tym, że ludzie zwykle go prześcigają, a problemy są takie same, jak na stronie internetowej. Możliwe bardzo proste opcje obejmują https dla kroku logowania, zwrot tokena, wymagają włączenia go do przyszłych żądań. Możesz również użyć podstawowego uwierzytelniania HTTP i po prostu przekazać rzeczy w nagłówku. Aby zwiększyć bezpieczeństwo, często obracaj / wygasaj tokeny, sprawdź, czy żądania przychodzą z tego samego bloku IP (może to być bałagan, gdy użytkownicy mobilni przemieszczają się między komórkami), połącz z kluczem API lub podobnym. Alternatywnie wykonaj krok oauth w kroku „klucz żądania” (ktoś zasugerował to już w poprzedniej odpowiedzi i jest to dobry pomysł) przed uwierzytelnieniem użytkownika i użyj go jako klucza wymaganego do wygenerowania tokena dostępu.

Alternatywą, z której jeszcze nie korzystałem, ale słyszałem wiele jako przyjazną dla urządzenia alternatywę dla oAuth, jest xAuth . Spójrz na to, a jeśli go użyjesz, będę bardzo zainteresowany, aby dowiedzieć się, jakie są twoje wrażenia.

Jeśli chodzi o haszowanie, sha1 jest nieco lepszy, ale nie rozłączaj się przy tym - cokolwiek urządzenia mogą łatwo (i szybko pod względem wydajności) wdrożyć, jest prawdopodobnie w porządku.

Mam nadzieję, że to pomoże, powodzenia :)

Lorna Mitchell
źródło
Dzięki za odpowiedzi. Patrzyłem na xAuth i może to być droga, którą wybieram, abym mógł zakończyć instalację oAuth, co zapewnia bardziej ustandaryzowany proces interakcji z API.
jsuggs
9

Czy szukasz mechanizmu uwierzytelniania po stronie serwera, który będzie obsługiwał aspekty uwierzytelniania i autoryzacji aplikacji mobilnej?

Zakładając, że tak jest, podszedłbym do tego w następujący sposób (ale tylko dlatego, że jestem programistą Java, więc facet z C # zrobiłby to inaczej):

Usługa uwierzytelniania i autoryzacji RESTful

  1. Będzie to działać tylko przez HTTPS, aby zapobiec podsłuchowi.
  2. Będzie on oparty na kombinacji RESTEasy , Spring Security i CAS (do pojedynczego logowania w wielu aplikacjach).
  3. Będzie działał zarówno z przeglądarkami, jak i aplikacjami klienckimi obsługującymi sieć
  4. Dostępny będzie internetowy interfejs zarządzania kontem, który pozwoli użytkownikom edytować swoje dane, a administratorzy (dla określonych aplikacji) zmieniają poziomy autoryzacji

Biblioteka / aplikacja bezpieczeństwa po stronie klienta

  1. Dla każdej obsługiwanej platformy (np. Symbian, Android, iOS itp.) Utwórz odpowiednią implementację biblioteki zabezpieczeń w rodzimym języku platformy (np. Java, ObjectiveC, C itp.)
  2. Biblioteka powinna zarządzać formowaniem żądań HTTPS przy użyciu dostępnych interfejsów API dla danej platformy (np. Java używa URLConnection itp.)
  3. Konsumenci z ogólnej biblioteki uwierzytelniania i autoryzacji (bo to wszystko, co to jest) koduje określony interfejs i nie będzie zadowolony, jeśli kiedykolwiek się zmieni, więc upewnij się, że jest bardzo elastyczny. Śledź istniejące opcje projektowania, takie jak Spring Security.

Więc teraz, kiedy widok z 30 000 stóp jest kompletny, jak sobie radzisz? Cóż, nie jest trudno stworzyć system uwierzytelniania i autoryzacji oparty na wymienionych technologiach po stronie serwera za pomocą klienta przeglądarki. W połączeniu z HTTPS frameworki zapewnią bezpieczny proces oparty na wspólnym tokenie (zwykle prezentowanym jako plik cookie) generowanym przez proces uwierzytelniania i używanym, gdy użytkownik chce coś zrobić. Ten token jest prezentowany przez klienta serwerowi za każdym razem, gdy ma miejsce jakiekolwiek żądanie.

W przypadku lokalnej aplikacji mobilnej wydaje się, że szukasz rozwiązania, które:

  1. Aplikacja kliencka ma zdefiniowaną listę kontroli dostępu (ACL) kontrolującą dostęp środowiska wykonawczego do wywołań metod. Na przykład, dany użytkownik może odczytać kolekcję z metody, ale jego ACL pozwala tylko na dostęp do obiektów, które mają Q w nazwie, więc niektóre dane w kolekcji są pobierane przez przechwytywacz bezpieczeństwa. W Javie jest to proste, wystarczy użyć adnotacji Spring Security w kodzie wywołującym i zaimplementować odpowiedni proces odpowiedzi ACL. W innych językach jesteś sam i prawdopodobnie będziesz musiał podać kod zabezpieczający, który wywołuje twoją bibliotekę zabezpieczeń. Jeśli język obsługuje AOP (Aspect Oriented Programming), użyj go w pełni w tej sytuacji.
  2. Biblioteka bezpieczeństwa buforuje pełną listę autoryzacji do swojej prywatnej pamięci dla bieżącej aplikacji, aby nie musiała pozostawać połączona. W zależności od długości sesji logowania może to być jednorazowa operacja, która nigdy się nie powtórzy.

Cokolwiek robisz, nie próbuj wymyślać własnego protokołu bezpieczeństwa ani nie używaj zabezpieczeń przez zaciemnienie. Nigdy nie będziesz w stanie napisać lepszego algorytmu niż te, które są obecnie dostępne i bezpłatne. Ponadto ludzie ufają dobrze znanym algorytmom. Jeśli więc powiesz, że twoja biblioteka zabezpieczeń zapewnia autoryzację i uwierzytelnianie dla lokalnych aplikacji mobilnych przy użyciu kombinacji SSL, HTTPS, SpringSecurity i tokenów szyfrowanych AES, natychmiast zyskasz wiarygodność na rynku.

Mam nadzieję, że to pomoże i powodzenia w przedsięwzięciu. Jeśli chcesz uzyskać więcej informacji, daj mi znać - napisałem sporo aplikacji internetowych opartych na Spring Security, listach ACL i tym podobnych.

Gary Rowe
źródło
Dzięki, dobra informacja. Kilka pytań. Po pierwsze, jeśli podsłuch jest akceptowalny (nie jestem pewien, czy to jest / nie jest, moja aplikacja na myśli nie zawiera żadnych prawdziwych osobistych / cennych informacji, ale jeśli zmieniłaby moje uzasadnienie), to czy HTTPS jest rzeczywiście wymagany?
jsuggs
Jeśli chcesz, możesz obsługiwać cały system poza HTTPS. HTTPS służy wyłącznie do ochrony tajnych informacji, więc zakładam, że podczas fazy uwierzytelniania zrobiłbyś to za pośrednictwem HTTPS, aby zapewnić pewną gwarancję, że twoja nazwa użytkownika / hasło / sekret są utrzymywane w tajemnicy. Po przekazaniu tokena w odpowiedzi można składać dalsze żądania, jeśli informacje zawarte w strumieniu (wymagały uwierzytelnienia w celu uzyskania) nie wymagają ochrony przed podsłuchującymi.
Gary Rowe,
Również ten opis protokołu uwierzytelniania CAS może być przydatny: jasig.org/cas/protocol
Gary Rowe
9

Twitter rozwiązał problem aplikacji zewnętrznej w oAuth, obsługując wariant, który nazywają xAuth . Niestety istnieje już wiele innych programów o tej nazwie, więc uporządkowanie może być mylące.

Protokół ma wartość oAuth, z tym wyjątkiem, że pomija fazę tokena żądania i po prostu natychmiast wydaje parę tokenów dostępu po otrzymaniu nazwy użytkownika i hasła. (Począwszy od kroku E tutaj .) Ta inicjał żądanie i odpowiedź muszą być zabezpieczone- wysyła nazwę użytkownika i hasło w postaci zwykłego tekstu oraz odbiera token dostępu i tajny token. Po skonfigurowaniu pary tokenów dostępu to, czy początkowa wymiana tokenów odbywała się za pomocą modelu oAuth, czy modelu xAuth, nie ma znaczenia zarówno dla klienta, jak i serwera przez resztę sesji. Ma to tę zaletę, że można wykorzystać istniejącą infrastrukturę oAuth i mieć prawie taką samą implementację dla aplikacji mobilnych / internetowych / stacjonarnych. Główną wadą jest to, że aplikacja ma dostęp do nazwy użytkownika i hasła klienta, ale wygląda na to, że twoje wymagania wymagają takiego podejścia.

W każdym razie chciałbym się zgodzić z twoją intuicją i intuicją kilku innych użytkowników: nie próbuj budować czegoś nowego od podstaw. Protokoły bezpieczeństwa mogą być łatwe do uruchomienia, ale zawsze są trudne do wykonania, a im bardziej skomplikowane, tym mniej prawdopodobne jest, że Twoi zewnętrzni programiści będą w stanie wdrożyć się przeciwko nim. Twój hipotetyczny protokół jest bardzo podobny do o (x) Auth - api_key / api_secret, nonce, sha1 hashed - ale zamiast być w stanie korzystać z jednej z wielu istniejących bibliotek, twoi programiści będą musieli stworzyć własne.

lantius
źródło
2
Powinienem również zauważyć, że wygląda na to, że punkt końcowy „token żądania pominięcia” będzie w oAuth 2, jest wymieniony w bieżącej wersji roboczej jako typ przyznania dostępu „hasłem”. Patrz sekcja 4.1.2: tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
lantius
Tak jak wspomniałem Lonrze, przyglądam się bardziej xAuth, a konkretnie z powodów, o których wspomniałeś na końcu ... programiści mogą „z półki” oAuth narzędzia / biblioteki do interakcji z moim API, co jest „dobrą rzeczą” .
jsuggs,
6

Bardzo późno na imprezę, ale chciałem dodać kilka dodatkowych punktów do rozważenia dla wszystkich zainteresowanych tym problemem. Pracuję dla firmy wykonującej rozwiązania bezpieczeństwa API mobilnych ( APVOV ), więc cały ten obszar jest zdecydowanie zgodny z moimi zainteresowaniami.

Na początek najważniejszą rzeczą do rozważenia przy zabezpieczaniu mobilnego interfejsu API jest to, ile jest ono warte . Właściwe rozwiązanie dla banku różni się od właściwego rozwiązania dla kogoś, kto po prostu robi rzeczy dla zabawy.

W proponowanym rozwiązaniu wspominasz, że wymagane będą co najmniej trzy parametry:

  • apikey - przekazywany programistom przy rejestracji
  • timestamp - podwaja się jako unikalny identyfikator każdej wiadomości dla danego apikey
  • hash - skrót mieszania znacznika czasu + apisecret

Oznacza to, że dla niektórych wywołań API nie jest wymagana nazwa użytkownika / hasło. Może to być przydatne w aplikacjach, w których nie chcesz wymuszać logowania (na przykład przeglądanie w sklepach internetowych).

Jest to nieco inny problem niż uwierzytelnianie użytkownika i bardziej przypomina uwierzytelnianie lub poświadczanie oprogramowania. Nie ma użytkownika, ale nadal chcesz się upewnić, że nie ma złośliwego dostępu do twojego API. Dlatego używasz swojego tajnego interfejsu API do podpisywania ruchu i identyfikowania kodu dostępu do interfejsu API jako autentycznego. Potencjalny problem z tym rozwiązaniem polega na tym, że musisz zdradzić sekret w każdej wersji aplikacji. Jeśli ktoś może wydobyć sekret, może użyć interfejsu API, podszywając się pod oprogramowanie, ale robiąc, co chce.

Aby przeciwdziałać temu zagrożeniu, możesz zrobić wiele rzeczy, w zależności od tego, jak cenne są dane. Zaciemnianie jest prostym sposobem na utrudnienie wydobycia sekretu. Istnieją narzędzia, które zrobią to za Ciebie, zwłaszcza w przypadku Androida, ale nadal musisz mieć kod, który generuje Twój skrót, a odpowiednio wykwalifikowana osoba zawsze może po prostu wywołać funkcję, która wykonuje skrót bezpośrednio.

Innym sposobem na ograniczenie nadmiernego użycia interfejsu API, który nie wymaga logowania, jest ograniczenie ruchu oraz potencjalna identyfikacja i blokowanie podejrzanych adresów IP. Ilość pracy, którą chcesz podjąć, będzie w dużej mierze zależeć od tego, jak wartościowe są twoje dane.

Poza tym możesz łatwo zacząć wchodzić w domenę mojej codziennej pracy. W każdym razie jest to kolejny aspekt zabezpieczania interfejsów API, który moim zdaniem jest ważny i chciał się zgłosić.

ThePragmatist
źródło