Jak zabezpieczyć interfejs API REST tylko dla zaufanych aplikacji mobilnych

96

Jak mogę się upewnić, że mój interfejs API REST odpowiada tylko na żądania generowane przez zaufanych klientów, w moim przypadku moje własne aplikacje mobilne? Chcę zapobiec niechcianym żądaniom pochodzącym z innych źródeł. Nie chcę, aby użytkownicy wpisywali klucz szeregowy lub cokolwiek innego, powinno to nastąpić za kulisami, podczas instalacji i bez wymaganej interakcji użytkownika.

O ile mi wiadomo, HTTPS służy wyłącznie do sprawdzania poprawności serwera, z którym się komunikujesz. Oczywiście używam HTTPS do szyfrowania danych.

Czy istnieje sposób na osiągnięcie tego?

Aktualizacja: użytkownik może wykonywać akcje tylko do odczytu, które nie wymagają zalogowania użytkownika, ale mogą także wykonywać akcje zapisu, które wymagają zalogowania użytkownika (uwierzytelnianie za pomocą tokena dostępu). W obu przypadkach chcę, aby interfejs API odpowiadał na żądania pochodzące tylko od zaufanych aplikacji mobilnych.

Interfejs API będzie również używany do rejestracji nowego konta za pośrednictwem aplikacji mobilnej.

Aktualizacja 2: Wygląda na to, że istnieje wiele odpowiedzi na to pytanie, ale szczerze mówiąc, nie wiem, którą z nich oznaczyć jako odpowiedź. Niektórzy twierdzą, że da się to zrobić, inni twierdzą, że nie da się tego zrobić.

Superkomórka
źródło
HTTPS używa SSL (i TLS). Protokół SSL / TLS może być używany z uwierzytelnianiem klienta.
atk
Masz na myśli certyfikaty SSL po stronie klienta? Myślę, że tego właśnie szukam, ale nie mam pojęcia, czy jest to w ogóle możliwe w aplikacjach mobilnych (Android i iOS)? Gdzie będzie przechowywany certyfikat klienta? Pamięć urządzenia, pamięć?
Supercell,
SSL będzie certyfikować tylko urządzenie mobilne, NIE aplikację mobilną.
Morons,
@Supercell: Dodam odpowiedź
atk

Odpowiedzi:

48

Nie możesz

Nigdy nie można zweryfikować encji, żadnej encji , czy to osoby, klienta sprzętowego czy oprogramowania. Możesz jedynie zweryfikować, czy to, co mówią , jest poprawne, a następnie przyjąć uczciwość .

Na przykład, skąd Google wie, że loguję się na swoje konto Gmail? Po prostu pytają mnie o nazwę użytkownika i hasło, sprawdzają to , a następnie zakładają uczciwość, bo kto inny miałby te informacje? W pewnym momencie Google zdecydowało, że to nie wystarczy i dodało weryfikację behawioralną (szukając dziwnych zachowań), ale nadal polega na osobie, która je wykonała , a następnie zweryfikowała zachowanie .

To jest dokładnie to samo z weryfikacją klienta. Możesz jedynie zweryfikować zachowanie klienta, ale nie samego klienta.

Dzięki SSL możesz sprawdzić, czy klient ma ważny certyfikat, czy nie, więc możesz po prostu zainstalować aplikację, uzyskać certyfikat, a następnie uruchomić cały nowy kod.

Pytanie brzmi: dlaczego to takie ważne? Jeśli to naprawdę niepokoi, kwestionowałbym twój wybór grubego klienta. Być może powinieneś skorzystać z aplikacji internetowej (abyś nie musiał ujawniać swojego interfejsu API).

Zobacz także: Pokonanie sprawdzania poprawności certyfikatu SSL dla aplikacji na Androida

oraz: Jak bezpieczne są certyfikaty SSL klienta w aplikacji mobilnej?

Kretynowie
źródło
1
Użyłem certyfikatów klienta na sprzęcie, na którym certyfikat był przechowywany na dysku zaszyfrowanym przez system operacyjny. Ale nawet tam nikt nie wierzył, że był niezawodny. Celem było utrudnienie zwykłym użytkownikom.
Steven Burnap,
1
@ Morons: aplikacja internetowa rozwiązałaby ten problem, ale uważamy, że użytkownicy będą bardziej skłonni do korzystania z aplikacji natywnej niż aplikacja internetowa (popraw mnie, jeśli nasze założenia są błędne). Powodem, dla którego jest to tak ważne, jest fakt, że interfejs API zapewnia użytkownikowi dostęp do części naszej bazy danych, która zawiera wiele danych zebranych przez miesiące pracy. Są to dane, które inne firmy lub użytkownicy mogą łatwo wykorzystać do własnych celów. Bez zabezpieczenia klientów nie wiedzielibyśmy, kto z nich korzysta (przeciwko nam).
Supercell,
6
Aplikacja internetowa nie rozwiązuje problemu. Modyfikowanie dowolnej strony klienckiej aplikacji WWW i dostosowywanie jej do własnych potrzeb jest dość trywialne.
Steven Burnap,
5
@Supercell Nie możesz pokazać komuś danych, a następnie uniemożliwić im udostępnianie. Jeśli nie chcesz, aby niektórzy posiadali Dane, nie dajesz im (pokaż) ich.
Morons,
Zgadzam się, ale z innego powodu. Możesz, jeśli masz kontrolę nad urządzeniami, RSA jest jak en.wikipedia.org/wiki/SecurID . Ale telefony komórkowe nie są czymś, co można kontrolować (mogą akceptować załącznik jak klucz wtyczki lub coś takiego).
imel96
31

Jestem pewien, że nie masz nic przeciwko logowaniu się użytkowników i komunikacji za pośrednictwem protokołu SSL, więc skupię się na tym, co uważam za bardziej interesującą część pytania: jak zapewnić, że Twoje działania tylko do odczytu - które mają nie wymagają użytkownika mają być uwierzytelnione - przyjmowane są wyłącznie z własnych aplikacji klienckich?

Przede wszystkim fNek wskazał na wcześniejszą odpowiedź - aplikacje klienckie znajdują się w rękach potencjalnie wrogich użytkowników. Można je badać, sprawdzać ich komunikację, dezasemblować kod. Nic, co zamierzam sugerować, nie pozwoli Ci zagwarantować, że ktoś nie dokona inżynierii wstecznej Twojego klienta i nie nadużyje interfejsu API REST. Ale powinno to stanowić barierę przed wszelkimi przypadkowymi próbami.

W każdym razie powszechnym podejściem jest:

  • Klient zawiera sekret
  • Podczas wysyłania żądania łączy parametry żądania z kluczami tajnymi i haszy wynik
  • Ten skrót jest wysyłany z żądaniem i sprawdzany przez serwer

np. wyobraź sobie GETprośbę o/products/widgets

Powiedzmy, że sekretem klienta jest „OH_HAI_I_IZ_SECRET”

Połącz czasownik HTTP, adres URL i klucz tajny:

GET/products/widgetsOH_HAI_I_IZ_SECRET

I weź skrót SHA-1 tego:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Następnie prześlij to, aby prośba dotyczyła:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Wreszcie, aby uniemożliwić komuś przynajmniej ponowne odtwarzanie indywidualnych żądań, weź również znacznik czasu i dodaj go do parametrów i skrótu. np. teraz, w czasie uniksowym, jest 1384987891. Dodaj to do konkatenacji:

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

Hash że:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

I wyślij:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

Serwer sprawdzi skrót, a także sprawdzi, czy znacznik czasu jest aktualny (np. W ciągu 5 minut, aby pozwolić zegarom nie być idealnie zsynchronizowanym)

Ostrzeżenie! Ponieważ mówisz o aplikacjach mobilnych, istnieje wyraźne ryzyko, że czyjś telefon będzie miał nieprawidłowy zegar. Lub niewłaściwa strefa czasowa. Lub coś. Dodanie czasu do skrótu prawdopodobnie złamie niektórych legalnych użytkowników, więc używaj tego pomysłu ostrożnie.

Carson63000
źródło
6
ten mechanizm mieszający może zrozumieć każdy programista, gdy rozbiera apk.
Punith Raj
8
@PunithRaj dokładnie, omówiłem to w drugim akapicie. „Nic, co zasugeruję, nie pozwoli Ci zagwarantować, że ktoś nie dokona inżynierii wstecznej Twojego klienta i nie nadużyje interfejsu API REST. Ale powinno to stanowić barierę przed wszelkimi przypadkowymi próbami”.
Carson63000,
dla ostrzeżenia, używam UTC na serwerze i telefonie komórkowym, to rozwiązuje problem, prawda?
shareef
@ Carson63000 - czy istnieje konkretne rozwiązanie? zwłaszcza dla interfejsu API rejestracji użytkownika, który musi być publicznie otwarty (użytkownik musi się zarejestrować, zanim będzie mógł się zalogować, w Internecie lub w aplikacji mobilnej) i może być celem botów, aby stworzyć tysiące fałszywych użytkowników.
Tohid
17

Wszystkim zainteresowanym na Androidzie MOŻESZ sprawdzić, czy otrzymane żądanie zostało wysłane z Twojej aplikacji.

Krótko mówiąc, przesyłając aplikację do Google, podpisujesz ją unikalnym kluczem, który jest znany tylko Tobie (i Google).

Proces weryfikacji przebiega następująco:

  1. Twoja aplikacja przechodzi do Google i prosi o token autoryzacji
  2. Twoja aplikacja bezpiecznie wysyła token do zaplecza
    1. Twój back-end przechodzi do Google i sprawdza token uwierzytelnienia otrzymany z Twojej aplikacji.
    2. wtedy zaplecze sprawdza, czy unikalny klucz podpisany przez aplikację pasuje, jeśli nie, oznacza to, że nie była to Twoja aplikacja ...

pełny blog, który to wyjaśnia i jak go wdrożyć, można znaleźć tutaj: http://android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-android.html

ndori
źródło
1
Dobra odpowiedź, jednak złośliwy użytkownik nadal może sfałszować aplikację przy wystarczającym wysiłku. ale nic nie jest naprawdę bezpieczne, nie chodzi o to, czy tylko o to, kiedy
Mate
1
W systemie iOS dostępna jest ta opcja: link Interfejsy API DeviceCheck pozwalają również sprawdzić, czy otrzymany token pochodzi z autentycznego urządzenia Apple, na które została pobrana Twoja aplikacja
Iwaz,
Wymaga kont (e-mail)
użytkownik25
5

Ok, więc warto wspomnieć, zanim zacznę, że w przypadku większości aplikacji jest to ogromna przesada. W większości przypadków wystarczy mieć jeden ważny certyfikat i / lub token. Jeśli wymaga to robienia czegoś tak trudnego, jak dekompilowanie aplikacji, nawet większość hakerów nie będzie się tym przejmować, chyba że podasz bardzo cenne dane. Ale hej, gdzie jest zabawa w tej odpowiedzi?

Możesz więc skonfigurować kryptografię asymetryczną, podobnie jak podpis cyfrowy używany do podpisywania programów. Każda aplikacja może następnie mieć indywidualny certyfikat, który jest wystawiany przez pojedynczy urząd certyfikacji i weryfikowany, gdy użytkownik się łączy. (przy pierwszej rejestracji lub przy pierwszej instalacji) Po uwierzytelnieniu tego certyfikatu możesz dodatkowo zabezpieczyć aplikację, rejestrując ten certyfikat jako ważny dla jednego określonego identyfikatora urządzenia (takiego jak identyfikator Android )

Tom Squires
źródło
5

Jak wspomniał @Morons w swojej odpowiedzi, bardzo trudno jest zweryfikować byt na drugim końcu połączenia.

Najprostszym sposobem na zapewnienie pewnego poziomu autentyczności jest sprawdzenie przez serwer jakiegoś sekretu, który zna tylko prawdziwa istota. Dla użytkownika może to być nazwa użytkownika i hasło. W przypadku oprogramowania, w którym nie ma użytkownika, możesz osadzić sekret.

Problem z tymi podejściami polega na tym, że musisz zaufać klientowi. Jeśli ktoś dokona inżynierii wstecznej Twojej aplikacji lub ukradnie hasło, może udawać, że jesteś Tobą.

Możesz podjąć kroki, aby utrudnić wydobycie tajnych informacji, zaciemniając je w pliku wykonywalnym. Narzędzia takie jak ProGuard, który jest zaciemniaczem dla Javy, mogą w tym pomóc, nie wiem zbyt wiele o zaciemnianiu w innych językach, ale prawdopodobnie istnieją podobne narzędzia. Korzystanie z połączenia TLS pomaga zapobiegać szpiegowaniu ruchu, ale nie zapobiega atakowi MITM. Przypinanie może pomóc rozwiązać ten problem.

Pracuję dla firmy o nazwie CriticalBlue (pełne ujawnienie!), Która ma produkt o nazwie Approov, który próbuje rozwiązać ten problem zaufania. Działa obecnie na Androida / iOS i zapewnia naszym serwerom mechanizm sprawdzania integralności aplikacji klienckiej. Robi to, zmuszając klienta do obliczenia odpowiedzi na losowe wyzwanie. Klient musi obliczyć odpowiedź za pomocą atrybutów zainstalowanego pakietu aplikacji, które są trudne do sfałszowania i zawiera kilka wyrafinowanych mechanizmów antysabotażowych.

Zwraca token, który można następnie przesłać jako dowód autentyczności do interfejsu API.

Ważną różnicą w tym podejściu jest to, że chociaż byłoby możliwe wyłączenie sprawdzania autentyczności na kliencie, to gdybyś to zrobił, nie dostaniesz tokena uwierzytelniającego, musisz zweryfikować swoją aplikację na serwerze. Biblioteka jest również ściśle związana z właściwościami pliku wykonywalnego, w którym się znajduje, więc bardzo trudno byłoby osadzić ją w fałszywej aplikacji i sprawić, by działała.

Istnieje analiza kosztów i korzyści, którą musi opracować każdy programista interfejsu API, aby zdecydować, jak prawdopodobne jest, że ktoś spróbuje zhakować swój interfejs API i jakie może to być kosztowne. Proste tajne sprawdzenie w aplikacji zapobiega trywialnym atakom, ale ochrona przed bardziej zdeterminowanym atakującym jest prawdopodobnie znacznie bardziej skomplikowana i potencjalnie kosztowna.

ThePragmatist
źródło
0

SSL zabezpieczy kanał komunikacji.

Pomyślne logowanie spowoduje wydanie tokena uwierzytelniającego zaszyfrowane połączenie.

Token uwierzytelnienia zostanie przekazany do interfejsu API REST we wszystkich kolejnych żądaniach.

CodeART
źródło
1
Dodałem kilka dodatkowych informacji. Planowałem przeprowadzić uwierzytelnianie, tak jak wspomniałeś, za pomocą tokena dostępu. Interfejs API REST nie wymaga zalogowania użytkownika, tylko w celu wykonania określonych czynności. W obu przypadkach klienci muszą być podpisani / zaufani.
Supercell,
Nie wiem wiele o natywnym tworzeniu aplikacji mobilnych, ale czy Twoja aplikacja mobilna może dostarczyć numer telefonu komórkowego do interfejsu API REST? Podczas instalowania aplikacji na telefonie z Androidem często jestem proszony o udzielenie aplikacji określonych uprawnień. Jeśli możesz wysłać numer telefonu komórkowego przy każdym żądaniu za pośrednictwem bezpiecznego połączenia, możesz odrzucić wszystkie żądania o nieznanym numerze telefonu komórkowego. Po prostu myślę tutaj głośno ...
CodeART
To może działać, ale wymagałoby zalogowania użytkownika i przypisania numeru do konta użytkownika. W przeciwnym razie serwer nie miałby nic do zweryfikowania numeru.
Supercell,
Jak zamierzasz zainstalować aplikację mobilną?
CodeART
Będą dostępne w sklepach z aplikacjami (Google, Apple, Microsoft)
Supercell,
0

Nie byłoby to zbyt bezpieczne, ale możesz dodać jakiś tajny kod lub nawet podpis cyfrowy. Wada: musi być uwzględniona w aplikacji, co ułatwia jej uzyskanie, jeśli wiesz, co robisz.

fNek
źródło
0

O ile mi wiadomo, HTTPS służy wyłącznie do sprawdzania poprawności serwera, z którym się komunikujesz.

W rzeczywistości można użyć protokołu SSL do uwierzytelnienia zarówno klienta, jak i serwera. Lub, inaczej mówiąc, „tak, możesz używać certyfikatów klienta”.

Musisz ...

  • spójrz na bibliotekę SSL, której używasz, aby określić, jak określić certyfikaty klienta na urządzeniu mobilnym,
  • napisz kod lub skonfiguruj serwer HTTPS, aby akceptował tylko połączenia od zaufanych, zarejestrowanych klientów.
  • wymyślić mechanizm dodawania zaufanych certyfikatów klienta do serwera
  • wymyślić mechanizm usuwania niezaufanych certyfikatów klienta z serwera

Aplikacja mobilna może przechowywać certyfikat w dowolnym miejscu. Ponieważ chcesz uwierzytelniania specyficznego dla aplikacji, powinieneś rozważyć przechowywanie certyfikatu w chronionym miejscu na dysku (w systemie Android możesz utworzyć tabelę „config” w bazie danych SQLite oraz wiersz dla certyfikatu i drugi dla klucza prywatnego) .

atk
źródło