Jak bezpiecznie przechowywać token dostępu i sekret w systemie Android?

124

Zamierzam używać protokołu OAuth do pobierania wiadomości i kontaktów z Google. Nie chcę za każdym razem prosić użytkownika o zalogowanie się w celu uzyskania tokena dostępu i sekretu. Z tego, co zrozumiałem, muszę je przechowywać w mojej aplikacji w bazie danych lub SharedPreferences. Ale martwię się trochę o aspekty bezpieczeństwa. Czytałem, że możesz zaszyfrować i odszyfrować tokeny, ale napastnikowi łatwo jest po prostu zdekompilować twój apk i klasy i uzyskać klucz szyfrowania.
Jaka jest najlepsza metoda bezpiecznego przechowywania tych tokenów w systemie Android?

Tak chłopie
źródło
1
Jak mogę przechowywać klucz klienta i sekret (ich twarda oprawa nie jest zabezpieczona)? Potrzebuję ich, aby zażądali dostępu do tokena i klucza tajnego. Jak robią to inne istniejące aplikacje korzystające z Oauth? hmm wreszcie z oauth, musisz zadbać o znacznie więcej kwestii bezpieczeństwa dla mnie ... muszę bezpiecznie przechowywać token konsumenta / w tajemnicy, a także dostęp i sekret ... wreszcie czy nie byłoby łatwiej po prostu przechowywać zaszyfrowaną nazwę użytkownika / hasło użytkownika? ... w końcu, czy to drugie nie jest lepsze? Po prostu nadal nie widzę, jak Oauth jest lepsze ...
yeahman
czy możesz mi powiedzieć, który plik przechowuje token dostępu? Jestem nowy na Androidzie i próbowałem uruchomić przykładową aplikację Plus, ale nie mogę znaleźć tego nigdzie [metoda GoogleAuthUtil.getToken ().]
Abhishek Kaushik

Odpowiedzi:

116

Przechowuj je jako wspólne preferencje . Są one domyślnie prywatne i inne aplikacje nie mają do nich dostępu. Na urządzeniach z dostępem do roota, jeśli użytkownik jawnie zezwala na dostęp do aplikacji, która próbuje je odczytać, aplikacja może z nich korzystać, ale nie można się przed tym chronić. Jeśli chodzi o szyfrowanie, musisz albo wymagać od użytkownika, aby za każdym razem wprowadzał hasło odszyfrowania (w ten sposób pokonując cel buforowania poświadczeń) lub zapisać klucz do pliku, a otrzymasz ten sam problem.

Przechowywanie tokenów zamiast rzeczywistego hasła z nazwą użytkownika ma kilka zalet:

  • Aplikacje innych firm nie muszą znać hasła, a użytkownik może być pewien, że wyślą je tylko do oryginalnej witryny (Facebook, Twitter, Gmail itp.)
  • Nawet jeśli ktoś ukradnie token, nie zobaczy hasła (którego użytkownik może używać również w innych witrynach)
  • Tokeny zazwyczaj mają żywotność i wygasają po pewnym czasie
  • Tokeny mogą zostać unieważnione, jeśli podejrzewasz, że zostały naruszone
Nikolay Elenkov
źródło
1
dzięki za odpowiedź! ale jak mogę się dowiedzieć, czy mój klucz klienta został naruszony? lol ciężko będzie powiedzieć ... ok, jeśli chodzi o przechowywanie tokena dostępu i tajnego klucza, ok, zapisuję je we wspólnych preferencjach i zaszyfruj je, ale co z kluczem klienta i sekretem? Nie mogę ich przechowywać we wspólnych preferencjach (musiałbym wyraźnie napisać klucz konsumenta i sekret w kodzie, aby zapisać go we wspólnych preferencjach w pierwszej kolejności) .. nie wiem, czy rozumiesz, o co mi chodzi.
yeahman
2
Musisz albo umieścić je w aplikacji w (nieco) zaciemniony sposób, aby nie były widoczne od razu po dekompilacji, lub użyć własnej aplikacji internetowej proxy do autoryzacji, która ma klucz i sekret. Umieszczenie ich w aplikacji jest oczywiście łatwiejsze, a jeśli uważasz, że ryzyko, że ktoś spróbuje złamać Twoją aplikację, jest wystarczająco niskie, zastosuj takie podejście. BTW, powyższe punkty dotyczą hasła użytkownika. Jeśli okaże się, że Twój klucz / klucz klienta został naruszony, możesz je również unieważnić (to oczywiście spowoduje uszkodzenie aplikacji).
Nikolay Elenkov
1
@NikolayElenkov: Napisałeś `` Jeśli chodzi o szyfrowanie, musisz albo wymagać od użytkownika, aby za każdym razem wprowadzał hasło odszyfrowania (w ten sposób pokonując cel buforowania poświadczeń), albo zapisać klucz do pliku, a otrzymasz ten sam problem. ' . Co się stanie, jeśli crackerzy odwrócą Twoją aplikację, aby dowiedzieć się, jak działa szyfrowanie? Twoja obrona może zostać złamana. Czy najlepiej jest przechowywać takie informacje (token, szyfrowanie ...) przy użyciu kodu natywnego?
anhldbk
1
Jeśli dane aplikacji zostaną wyczyszczone, token odświeżania zostanie utracony, co prawdopodobnie nie jest tym, czego chciał użytkownik.
rds
2
To nie jest najlepszy sposób na przechowywanie tokenów w dzisiejszych czasach!
Rahul Rastogi
19

Możesz je przechowywać w AccountManager . Według tych gości jest to najlepsza praktyka.

wprowadź opis obrazu tutaj

Oto oficjalna definicja:

Ta klasa zapewnia dostęp do scentralizowanego rejestru kont online użytkowników. Użytkownik wprowadza dane uwierzytelniające (nazwę użytkownika i hasło) raz na konto, przyznając aplikacjom dostęp do zasobów online po zatwierdzeniu „jednym kliknięciem”.

Szczegółowy przewodnik dotyczący korzystania z Menedżera kont:

Jednak ostatecznie AccountManager przechowuje twój token tylko jako zwykły tekst. Dlatego zasugerowałbym zaszyfrowanie swojego sekretu przed zapisaniem ich w AccountManager. Możesz skorzystać z różnych bibliotek szyfrowania, takich jak AESCrypt lub AESCrypto

Inną opcją jest użycie biblioteki Conceal . Jest wystarczająco bezpieczny dla Facebooka i znacznie łatwiejszy w użyciu niż AccountManager. Oto fragment kodu umożliwiający zapisanie tajnego pliku za pomocą funkcji Conceal.

byte[] cipherText = crypto.encrypt(plainText);
byte[] plainText = crypto.decrypt(cipherText);
aldok
źródło
2
Dobra wskazówka, która ukrywa. Wygląda na bardzo łatwą w użyciu. I w wielu przypadkach użycia.
Lagos
Nie można znaleźć Conceal za pośrednictwem linku. Można ją dezaktywować
użytkownik1114
11

SharedPreferences nie jest samo w sobie bezpieczną lokalizacją. Na zrootowanym urządzeniu możemy łatwo odczytywać i modyfikować pliki SharedPrefereces xml wszystkich aplikacji. Dlatego tokeny powinny stosunkowo często tracić ważność. Ale nawet jeśli token traci ważność co godzinę, nowsze tokeny nadal mogą zostać skradzione z SharedPreferences. Android KeyStore służy do długoterminowego przechowywania i pobierania kluczy kryptograficznych, które posłużą do zaszyfrowania naszych tokenów w celu ich przechowywania np. W SharedPreferences lub w bazie danych. Klucze nie są przechowywane w procesie aplikacji, więc trudniej jest je złamać.

Ważniejsze od miejsca jest to, w jaki sposób mogą one same być bezpieczne, np. Przy użyciu podpisanych kryptograficznie krótkotrwałych JWT, szyfrowanie ich za pomocą Android KeyStore i wysyłanie ich za pomocą bezpiecznego protokołu

apex39
źródło
9
Więc gdzie możemy je przechowywać?
Milind Mevada
2
  1. W panelu projektów w Android Studio wybierz „Pliki projektu” i utwórz nowy plik o nazwie „keystore.properties” w katalogu głównym projektu.

wprowadź opis obrazu tutaj

  1. Otwórz plik „keystore.properties” i zapisz w nim swój token dostępu i klucz tajny.

wprowadź opis obrazu tutaj

  1. Teraz załaduj odczytany token dostępu i klucz tajny w pliku build.gradle modułu aplikacji . Następnie musisz zdefiniować zmienną BuildConfig dla tokenu dostępu i klucza tajnego, aby mieć do nich bezpośredni dostęp z poziomu kodu. Twój plik build.gradle może wyglądać następująco:

    ... ... ... 
    
    android {
        compileSdkVersion 26
    
        // Load values from keystore.properties file
        def keystorePropertiesFile = rootProject.file("keystore.properties")
        def keystoreProperties = new Properties()
        keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    
        defaultConfig {
            applicationId "com.yourdomain.appname"
            minSdkVersion 16
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            // Create BuildConfig variables
            buildConfigField "String", "ACCESS_TOKEN", keystoreProperties["ACCESS_TOKEN"]
            buildConfigField "String", "SECRET", keystoreProperties["SECRET"]
        }
    }
    
  2. Możesz użyć tokena dostępu i klucza tajnego w swoim kodzie w następujący sposób:

    String accessToken = BuildConfig.ACCESS_TOKEN;
    String secret = BuildConfig.SECRET;
    

W ten sposób nie musisz przechowywać tokenu dostępu i klucza tajnego w postaci zwykłego tekstu w projekcie. Więc nawet jeśli ktoś zdekompiluje twój APK, nigdy nie otrzyma twojego tokena dostępu i tajnego, gdy ładujesz je z zewnętrznego pliku.

Zahidur Rahman Faisal
źródło
1
Wygląda na to, że nie ma różnicy, że utworzenie pliku właściwości zamiast twardego kodowania.
Dzshean
Chcę napisać token w czasie wykonywania, może być to, że mój token jest zmieniany za każdym razem, gdy otwieram aplikację.
Rehan Sarwar
1
To bardzo dobry sposób na przechowywanie niektórych tokenów, takich jak tokeny dostępu do API. jeśli chcesz przechowywać poświadczenia użytkownika, NDK jest lepszym sposobem.
Eric
7
Absolutnie nie należy w ten sposób zachowywać poufnych informacji w swojej aplikacji! Nawet jeśli repozytorium nie zawiera danych przy użyciu tego podejścia (dane są wprowadzane do procesu kompilacji), generuje to plik BuildConfig, który ma token / sekret w postaci zwykłego tekstu, aby wszyscy mogli go zobaczyć po prostej dekompilacji.
Hrafn
-1

Cóż, możesz zabezpieczyć swój token dostępu, wykonując dwie opcje.

  1. Użyj opcji Zapisz swój token dostępu w magazynie kluczy Androida, którego nie można cofnąć.
  2. Użyj funkcji NDK z pewnymi obliczeniami, które zapisują twój token i NDK z kodem C ++, który jest bardzo trudny do odwrócenia
M.Noman
źródło