Większość twórców aplikacji zintegruje niektóre biblioteki stron trzecich ze swoimi aplikacjami. Jeśli ma to uzyskać dostęp do usługi, takiej jak Dropbox lub YouTube, lub do rejestrowania awarii. Liczba bibliotek i usług stron trzecich jest oszałamiająca. Większość tych bibliotek i usług jest zintegrowana poprzez uwierzytelnianie w usłudze, w większości przypadków odbywa się to za pomocą klucza API. Ze względów bezpieczeństwa usługi zwykle generują klucz publiczny i prywatny, często określany również jako klucz tajny. Niestety, aby połączyć się z usługami, ten klucz prywatny musi zostać użyty do uwierzytelnienia, a zatem prawdopodobnie jest częścią aplikacji. Nie trzeba dodawać, że ma to ogromny problem z bezpieczeństwem. Publiczne i prywatne klucze API można wyodrębnić z APK w ciągu kilku minut i można je łatwo zautomatyzować.
Zakładając, że mam coś podobnego do tego, w jaki sposób mogę chronić tajny klucz:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
Jaki jest Twoim zdaniem najlepszy i najbezpieczniejszy sposób przechowywania klucza prywatnego? Zaciemnianie, szyfrowanie, co myślisz?
źródło
Odpowiedzi:
W tej chwili skompilowana aplikacja zawiera ciągi kluczy, ale także stałe nazwy APP_KEY i APP_SECRET. Wydobywanie kluczy z takiego samodokumentującego się kodu jest banalne, na przykład w przypadku standardowego narzędzia Android dx.
Możesz zastosować ProGuard. Pozostawi nietknięte ciągi klawiszy, ale usunie stałe nazwy. W miarę możliwości zmieni także nazwy klas i metod krótkimi, pozbawionymi znaczenia nazwami. Wyodrębnienie kluczy zajmuje trochę więcej czasu, aby dowiedzieć się, który ciąg znaków służy do którego celu.
Pamiętaj, że konfiguracja ProGuard nie powinna być tak trudna, jak się obawiasz. Na początek wystarczy włączyć ProGuard, jak opisano w project.properties. Jeśli występują jakiekolwiek problemy z bibliotekami stron trzecich, być może będziesz musiał ukryć niektóre ostrzeżenia i / lub zapobiec ich zaciemnieniu, w proguard-project.txt. Na przykład:
To podejście oparte na brutalnej sile; możesz sprecyzować taką konfigurację po uruchomieniu przetworzonej aplikacji.
Możesz zaciemnić ciągi ręcznie w kodzie, na przykład przy użyciu kodowania Base64 lub najlepiej za pomocą czegoś bardziej skomplikowanego; może nawet natywny kod. Haker będzie musiał następnie statycznie poddać inżynierii wstecznej kodowanie lub dynamicznie przechwycić dekodowanie w odpowiednim miejscu.
Możesz zastosować komercyjny zaciemniacz, taki jak wyspecjalizowany rodzeństwo DexGuard firmy ProGuard . Może dodatkowo zaszyfrować / zaciemnić ciągi i klasy. Wydobycie kluczy zajmuje jeszcze więcej czasu i wiedzy.
Możliwe, że możesz uruchomić części aplikacji na własnym serwerze. Jeśli możesz zatrzymać klucze, są one bezpieczne.
W końcu musisz dokonać ekonomicznego kompromisu: jak ważne są klucze, ile czasu lub oprogramowania możesz sobie pozwolić, jak wyrafinowani są hakerzy zainteresowani kluczami, ile czasu będą chcieli wydać, ile warte jest opóźnienie przed zhakowaniem kluczy, na jaką skalę hakerzy z powodzeniem rozprowadzą klucze itp. Małe fragmenty informacji, takie jak klucze, są trudniejsze do ochrony niż całe aplikacje. Zasadniczo nic po stronie klienta nie jest nie do złamania, ale z pewnością możesz podnieść poprzeczkę.
(Jestem programistą ProGuard i DexGuard)
źródło
Kilka pomysłów, moim zdaniem tylko pierwszy daje pewną gwarancję:
Zachowaj swoje sekrety na jakimś serwerze w Internecie, a kiedy zajdzie taka potrzeba, po prostu je złap i użyj. Jeśli użytkownik ma zamiar użyć Dropbox, nic nie powstrzyma Cię przed wysłaniem żądania do Twojej witryny i zdobyciem tajnego klucza.
Umieść swoje sekrety w kodzie jni, dodaj zmienny kod, aby Twoje biblioteki były większe i trudniejsze do dekompilacji. Możesz także podzielić ciąg kluczy na kilka części i przechowywać je w różnych miejscach.
użyj obfuscatora, również wprowadź tajny kod, a później go odblokuj, gdy będzie to konieczne.
Umieść swój tajny klucz jako ostatnie piksele jednego ze swoich obrazów w zasobach. W razie potrzeby przeczytaj go w kodzie. Ukrywanie kodu powinno pomóc ukryć kod, który będzie go czytał.
Jeśli chcesz szybko sprawdzić, jak łatwo można odczytać kod apk, pobierz APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
źródło
Innym podejściem jest przede wszystkim nie mieć tajemnicy na urządzeniu! Zobacz techniki bezpieczeństwa Mobile API (szczególnie część 3).
Korzystając z uświęconej tradycji pośrednictwa, udostępnij tajemnicę między punktem końcowym interfejsu API a usługą uwierzytelniania aplikacji.
Gdy klient chce nawiązać połączenie API , prosi usługę uwierzytelniania aplikacji o jego uwierzytelnienie (przy użyciu silnych technik zdalnej atestacji) i otrzymuje ograniczony czasowo (zwykle JWT ) token podpisany przez klucz tajny.
Token jest wysyłany przy każdym wywołaniu interfejsu API, w którym punkt końcowy może zweryfikować swój podpis przed podjęciem działania na żądanie.
Rzeczywisty sekret nigdy nie jest obecny na urządzeniu; w rzeczywistości aplikacja nigdy nie ma pojęcia, czy jest poprawna, czy nie, blokuje żądania uwierzytelnienia i przekazuje otrzymany token. Jako miła korzyść z pośrednictwa, jeśli kiedykolwiek chcesz zmienić sekret, możesz to zrobić bez konieczności aktualizowania zainstalowanych aplikacji przez użytkowników.
Więc jeśli chcesz chronić swój sekret, nie posiadanie go w aplikacji to całkiem dobry sposób.
źródło
Stary niezabezpieczony sposób:
Wykonaj 3 proste kroki, aby zabezpieczyć interfejs API / tajny klucz ( stara odpowiedź )
Możemy użyć Gradle do zabezpieczenia klucza API lub tajnego klucza.
1. gradle.properties (właściwości projektu): Utwórz zmienną za pomocą klucza.
2. build.gradle (Module: app): Ustaw zmienną w build.gradle, aby uzyskać do niej dostęp w działaniu lub fragmencie. Dodaj poniższy kod do buildTypes {}.
3. Uzyskaj do niego dostęp w Activity / Fragment przez BuildConfig aplikacji:
Aktualizacja :
Powyższe rozwiązanie jest przydatne w projekcie open source do zatwierdzenia przez Git. (Podziękowania dla Davida Rawsona i riyaz-ali za komentarz).
Zgodnie z komentarzami Matthew i Pablo Cegarra powyższy sposób nie jest bezpieczny, a Dekompilator pozwoli komuś zobaczyć BuildConfig za pomocą naszych tajnych kluczy.
Rozwiązanie :
Możemy użyć NDK do zabezpieczenia kluczy API. Możemy przechowywać klucze w natywnej klasie C / C ++ i uzyskiwać do nich dostęp w naszych klasach Java.
Śledź tego bloga, aby zabezpieczyć klucze API za pomocą NDK.
Dalsze informacje na temat bezpiecznego przechowywania tokenów w systemie Android
źródło
gradle.properties
nie należy rejestrować w Git, więc jest to sposób na zachowanie tajemnicy poza popełnionym kodem źródłowym, przynajmniejapk
to dołączenia klucza API do wynikowego (zostanie dodany do wygenerowanegoBuildConfig
pliku), chociaż zdecydowanie jest to dobry pomysł na zarządzanie różnymi kluczami API (na przykład w projekcie open source)BuildConfig.java
plik będzie miał klucz w postaci zwykłego tekstu. Nie jest to lepsze niż to, co już robi PO.dla tych facetów to się nie ukryje, zablokuj albo
ProGuard
kod. Jest to refaktor, a niektóre płatne zaciemnienia wstawiają kilka bitowych operatorów, aby odzyskaćjk433g34hg3
ciąg. Możesz przerwać hakowanie o 5-15 minut, jeśli pracujesz 3 dni :)Najlepszym sposobem jest zachować go takim, jaki jest, imho.
Nawet jeśli przechowujesz po stronie serwera (komputer), klucz można zhakować i wydrukować. Może to trwa najdłużej? W każdym razie jest to kwestia kilku minut lub kilku godzin w najlepszym przypadku.
Normalny użytkownik nie zdekompiluje twojego kodu.
źródło
Jednym z możliwych rozwiązań jest zakodowanie danych w aplikacji i użycie dekodowania w czasie wykonywania (gdy chcesz użyć tych danych). Polecam również użyć progaurd, aby utrudnić odczytanie i zrozumienie zdekompilowanego kodu źródłowego twojej aplikacji. na przykład umieściłem zakodowany klucz w aplikacji, a następnie użyłem metody dekodowania w mojej aplikacji, aby zdekodować moje tajne klucze w czasie wykonywania:
Zdekompilowany kod źródłowy zaawansowanej aplikacji jest następujący:
Przynajmniej jest to dla mnie wystarczająco skomplikowane. tak właśnie robię, gdy nie mam wyboru, ale przechowuję wartość w mojej aplikacji. Oczywiście wszyscy wiemy, że to nie jest najlepszy sposób, ale dla mnie działa.
Wersja zdekompilowana:
i możesz znaleźć tak wiele klas szyfrujących za pomocą małego wyszukiwania w Google.
źródło
Dodając do rozwiązania @Manohar Reddy, bazy danych Firebase lub FireCase RemoteConfig (z wartością domyślną Null) można użyć:
Co różni się w tym rozwiązaniu?
źródło
Ten przykład ma wiele różnych aspektów. Wspomnę o kilku kwestiach, które moim zdaniem nie zostały wyraźnie omówione w innym miejscu.
Ochrona tajemnicy podczas transportu
Pierwszą rzeczą, na którą należy zwrócić uwagę, jest dostęp do interfejsu API Dropbox przy użyciu uwierzytelniania aplikacji mechanizmu wymaga przesłania klucza i tajnego klucza. Połączenie to HTTPS, co oznacza, że nie można przechwycić ruchu bez znajomości certyfikatu TLS. Zapobiega to przechwyceniu i odczytaniu pakietów przez osobę podróżującą z urządzenia mobilnego na serwer. Dla zwykłych użytkowników jest to naprawdę dobry sposób na zapewnienie prywatności ich ruchu.
To, co nie jest dobre, polega na zapobieganiu pobieraniu aplikacji i sprawdzaniu ruchu przez złośliwą osobę. Naprawdę łatwo jest korzystać z pośredniczącego proxy dla całego ruchu do i z urządzenia mobilnego. W tym przypadku nie wymaga demontażu ani inżynierii wstecznej kodu, aby wyodrębnić klucz aplikacji i klucz tajny ze względu na charakter interfejsu API Dropbox.
Możesz wykonać przypinanie, które sprawdza, czy certyfikat TLS otrzymany z serwera jest tym, którego oczekujesz. To dodaje kontrolę do klienta i utrudnia przechwytywanie ruchu. Utrudniłoby to kontrolę ruchu w locie, ale kontrola pinowania ma miejsce u klienta, więc prawdopodobnie nadal można wyłączyć test pinowania. Utrudnia to jednak.
Ochrona sekretu w spoczynku
Pierwszym krokiem jest użycie czegoś takiego jak proguard , który sprawi, że będzie mniej oczywiste, gdzie kryją się jakieś tajemnice. Możesz także użyć NDK do przechowywania klucza i tajemnicy oraz bezpośredniego wysyłania wniosków, co znacznie zmniejszy liczbę osób posiadających odpowiednie umiejętności do wydobywania informacji. Dalsze zaciemnianie można osiągnąć, nie przechowując wartości bezpośrednio w pamięci przez dłuższy czas, możesz je zaszyfrować i odszyfrować tuż przed użyciem, jak sugeruje inna odpowiedź.
Bardziej zaawansowane opcje
Jeśli masz teraz obsesję na punkcie umieszczenia sekretu w dowolnym miejscu w swojej aplikacji i masz czas i pieniądze na inwestowanie w bardziej kompleksowe rozwiązania, możesz rozważyć przechowywanie poświadczeń na swoich serwerach (zakładając, że je masz). Zwiększy to opóźnienie wszelkich wywołań interfejsu API, ponieważ będzie on musiał komunikować się za pośrednictwem serwera, i może zwiększyć koszty prowadzenia usługi z powodu zwiększonej przepustowości danych.
Następnie musisz zdecydować, jak najlepiej komunikować się z serwerami, aby zapewnić ich ochronę. Jest to ważne, aby zapobiec ponownemu pojawieniu się tych samych problemów z wewnętrznym interfejsem API. Najlepszą ogólną zasadą, jaką mogę podać, to nie przekazywać żadnych tajemnic bezpośrednio z powodu zagrożenia „człowiek w środku”. Zamiast tego możesz podpisać ruch przy użyciu swojego tajnego klucza i zweryfikować integralność wszelkich żądań przychodzących na twój serwer. Jednym ze standardowych sposobów jest obliczenie HMAC wiadomości wpisanej w tajny klucz. Pracuję w firmie, która ma produkt zabezpieczający, który również działa w tej dziedzinie, dlatego takie rzeczy mnie interesują. W rzeczywistości, oto artykuł na blogu jednego z moich kolegów, który omawia większość tego.
Ile powinienem zrobić?
W przypadku takich porad dotyczących bezpieczeństwa musisz podjąć decyzję dotyczącą kosztów / korzyści dotyczącą tego, jak bardzo chcesz zmusić kogoś do włamania. Jeśli jesteś bankiem chroniącym miliony klientów, twój budżet jest zupełnie inny niż ktoś, kto wspiera aplikację w ich wolny czas. Jest praktycznie niemożliwe, aby uniemożliwić komuś złamanie twojego bezpieczeństwa, ale w praktyce niewiele osób potrzebuje wszystkich dzwonków i gwizdków, a przy pewnych podstawowych środkach ostrożności można uzyskać długą drogę.
źródło
Najbezpieczniejszym rozwiązaniem jest przechowywanie kluczy na serwerze i kierowanie wszystkich żądań wymagających tego klucza przez serwer. W ten sposób klucz nigdy nie opuszcza twojego serwera, więc tak długo, jak długo twój serwer jest bezpieczny, tak i twój klucz. Oczywiście z tym rozwiązaniem wiąże się koszt wydajności.
źródło
Zachowaj tajemnicę
firebase database
i wyjdź z niej, gdy aplikacja się uruchomi. Jest to o wiele lepsze niż wywoływanie usługi internetowej.źródło
Cokolwiek zrobisz, aby zabezpieczyć swoje tajne klucze, nie będzie prawdziwym rozwiązaniem. Jeśli programista może zdekompilować aplikację, nie ma sposobu, aby zabezpieczyć klucz, ukrycie klucza to po prostu bezpieczeństwo przez zaciemnienie, podobnie jak zaciemnienie kodu. Problem z zabezpieczeniem tajnego klucza polega na tym, że aby go zabezpieczyć, musisz użyć innego klucza i ten klucz również musi być zabezpieczony. Pomyśl o kluczu ukrytym w pudełku zamkniętym kluczem. Umieszczasz pudełko w pokoju i zamykasz pokój. Pozostaje ci kolejny klucz do zabezpieczenia. I ten klucz będzie nadal zakodowany na stałe w twojej aplikacji.
Więc dopóki użytkownik nie wprowadzi kodu PIN lub frazy, nie ma sposobu, aby ukryć klucz. Ale aby to zrobić, musiałbyś mieć schemat zarządzania PIN-ami występującymi poza pasmem, co oznacza przez inny kanał. Z pewnością nie jest praktyczne do zabezpieczania kluczy do usług takich jak interfejsy API Google.
źródło
Wiekowy post, ale wciąż wystarczająco dobry. Myślę, że ukrywanie go w bibliotece .so byłoby świetne, oczywiście przy użyciu NDK i C ++. Pliki .so można wyświetlać w edytorze szesnastkowym, ale powodzenia przy dekompilacji: P
źródło
Jedynym prawdziwym sposobem na zachowanie tych prywatności jest zachowanie ich na serwerze, a aplikacja wysyła wszystko na serwer, a serwer wchodzi w interakcję z Dropbox. W ten sposób NIGDY nie dystrybuujesz swojego klucza prywatnego w jakimkolwiek formacie.
źródło
W oparciu o gorzkie doświadczenia i po konsultacji z ekspertem IDA-Pro najlepszym rozwiązaniem jest przeniesienie kluczowej części kodu do DLL / SharedObject, a następnie pobranie go z serwera i załadowanie w czasie wykonywania.
Wrażliwe dane muszą zostać zakodowane, ponieważ bardzo łatwo jest zrobić coś takiego:
źródło