Zapisywanie danych w KeyChain iOS

13 grudnia 2017
Read this article in English here 🇬🇧

Gdzie trzymać dane użytkownika na urządzeniu? To jedna z najczęściej poruszanych kwestii dotyczących bezpieczeństwa przetrzymywania danych. Niestety, wciąż bez dobrej odpowiedzi. Zdaża się tak, że wasz back-end nie wdrożył rozwiązania umożliwiającego przechowywanie na urządzeniu np. tylko Hashy dla haseł, albo zachodzi potrzeba, aby aplikacja umożliwiała korzystanie z więcej niż jednego konta. Co za tym idzie, trzeba jakoś się zautoryzować z systemem 🤔.

W dzisiejszym wpisie pokażę Ci czym właściwie jest Pęk kluczy w systemie iOS, jak z niego korzystać, oraz kilka best practice dotyczących przechowywania wrażliwych danych na urządzeniu. Brzmi ok👍? No to do dzieła 🚀.

pek kluczy

Czym jest Pęk kluczy (KeyChain) ?

System iOS posiada taką ciekawą rzecz, jaką jest pęk kluczy (ang. key chain) 🔐. Jest to nic innego jak baza danych przechowująca wszystkie newralgiczne dane użytkownika, takie jak loginy, hasła czy certyfikaty.

Pytanie drugie, od razu nasuwające się na myśl – dlaczego niby pęk kluczy jest bezpieczny?
Ponieważ key chain korzysta z szyfrowania kompleksowego, tz. dane w nim zawarte są zabezpieczone przy użyciu klucza tworzonego na podstawie informacji unikalnych dla urządzenia oraz kodu tegoż urządzenia, który znany jest jego właścielowi. Minimalny algorytm szyfrowania danych to AES z kluczem 128-bitowym.

Od roku 2016 Apple włączyło usługę Key chain w iCloud – to oznacza, że możesz współdzielić swój pęk kluczy pomiedzy swoimi urządzeniami w ramach jednego AppleID.

Hm… niby wszystko lata i synchronizuje z użyciem szyforwania TLS w wersji 1.2 (DOC), ale mimo wszystko świadomość tego, że plik z pękiem kluczy jest trzymany gdzieś na serwerach Apple nie napawa mnie radością… jakoś nie jestem przekonany do tego rozwiązania, ale to pozostawiam do twojego wyboru.

Więcej informacji na temat pęku kluczy znajdziesz w dziale supportu tutaj: Support

Co trzymać w pęku kluczy?

Pęk kluczy to jedyne względnie bezpieczne miejsce do przetrzymywania danych wrażliwych. Ogólnie dane konfiguracyjne zapewne przechowujesz w UserDefaults. I tutaj już tak pięknie nie jest, bo dane tam zapisane są w dosyć prosty sposób możliwe do odczytania przez osobę z dostępem do twojego urządzenia. Za to bez twojego hasła nikt niepowołany nie dostanie się do pęku kluczy.

No dobra, to co powinniśmy trzymać w pęku kluczy?

  • loginy i hasła (najlepiej hashe)
  • dane płatności
  • klucze do algorytmów szyfrujących
  • Jak mi się coś przypomni to wyedytuje i dodam… 😎

Trzymanie danych w pęku kluczy ma jeszcze jedną zaletę – w przypadku np. kiedy użytkownik odinstaluje apkę i zainstaluje za jakiś czas ponownie, w dalszym ciągu będzie miał dostęp do danych zapisanych wcześniej w pęku kluczy (o ile ich ręcznie nie usunie 😅).

Dostęp do pęku kluczy

Ok, czas na trochę kodziwa. Dostęp do pęku kluczy jest prosty do zainplementowania. Większość robi za nas Apple ➡️ należy bowiem pobrać sobie Sample Code stąd i cały plik wkleić do naszego projektu. Ja zawsze tworzę sobie również pomocniczą strukturę do późniejszej konfiguracji.


struct KeychainConfiguration {
    static let serviceName = "SercureStore"            
    static let accessGroup: String? = nil
}

Ok, mamy arsenał, czas na wykorzystanie 🔫. Na początek zapisywanie danych w pęku kluczy.
NOTE: W tym artykule skupiam sie na korzystaniu z pęku kluczy, dlatego zapisuję hasła jako zwykły String. Pamiętaj jednak o przechowywaniu kluczy w postaci zaszyfrowanej.


func setPasswordToKeychain(login: String, pass: String){
    do{
        let passwordItem = KeychainPasswordItem(service: KeychainConfiguration.serviceName,
                                           account: login,
                                           accessGroup: KeychainConfiguration.accessGroup)
                
        // Save in keychain
        try passwordItem.savePassword(pass)
    }catch { print(error.localizedDescription) }
}        

Funkcja setPasswordToKeychain() tworzy obiekt pęku kluczy dla naszego loginu, a następnie zapisuje do niego hasło przez metodę savePassword(). Metoda zapisu może zwrócić błąd, stąd całość znajduję się wewnątrz konstrukcji docatch.

Jest, działa, fajnie 😁. Teraz chcę pobrać hasło z pęku kluczy dla danego loginu użytkownika. Tworzę zatem funkcję getPassword():

func getPassword(forUser user: String) -> String? { }

Prosta sprawa – metoda przyjmuję jako parametr login user’a a zwróci hasło z pęku kluczy lub nil, jeżeli nie posiada hasła dla użytkownika.


func getPassword(forUser user: String) -> String? {
    do {
        let passwordItem = KeychainPasswordItem(service: KeychainConfiguration.serviceName,
                                                account: user,
                                                accessGroup: KeychainConfiguration.accessGroup)
                
        // Read password form Keychain
        let pass = try passwordItem.readPassword()
                
        return pass
        
        }
                
    } catch { print(error.localizedDescription) }
    return nil
}

I już. Tak to działa. Oczywiście ten przykład pokazuje wyłącznie samą mechanikę zapisu i odczytu danych. Pamiętaj, że całość warto również zabezpieczyć, np. przez implementację TouchID do odblokowania pęku kluczy oraz szyfrowaniu danych użytkownika.

Co jeszcze umie pęk kluczy?

Jako ciekawska osoba zapewne już wcześniej zaglądałeś do skopiownego pliku z kodem od Apple. Jak widzisz, znajdują się tam również inne metody i funkcje pokazujące możliwości keychain’a. Poza odczytaniem hasła możesz też zmienić nazwę konta (czyli de facto login dla danego hasła):

mutating func renameAccount(_ newAccountName: String) throws

lub usunąć cały obiekt:

func deleteItem() throws

Samo użycie pęku kluczy jest bardzo proste i nie wymaga zbyt dużo kodu. Pamiętaj jeszcze o jednej ważnej rzeczy – nie hard-code’uj żadnych danych, np. haseł czy kluczy algorytmów. Te dane powinny być generowane w locie (w tzw. runtime) lub pobierane z serwera, np. w postaci tokena.

O samym szyfrowaniu i dobrych praktykach z tym związanych będę pisał za niedługo oddzielny artykuł, więc wytłumacze Ci to dokładnie.

Podsumowanie

Ogólne wniosku są proste – nie przetrzymuj haseł użytkownika na urządzeniu, jeśli nie musisz.
A jeśli już musisz, to używaj do tego pęku kluczy oraz różnych sposobów szyfrowania tych danych.

Co do samego pęku kluczy – jak widzisz jest to proste do implementacji i nie wymaga tajemnej wiedzy, a groźne jest tylko z nazwy. Temat bezpieczeństwa danych jest bardzo gorący, dlatego powinieneś zawsze dołożyć wszelkich starań aby w najlepszy możliwy sposób dbać o dane swoich użytkowników.

Jak zawsze w tym miejscu dziękuję Ci za wizytę i czytanie 👍. Mam nadzieję że dzisiejszy wpis był dla Ciebie pomocny. Prośba o podzielenie się komentarzem lub spostrzeżeniem w komentarzu pod postem, lub na którejś społecznościówce 👉 Twitter, Instagram, Snapchat albo na grupie na Facebook.

Dzięki i do nastepnego 💻 !
@jkornat


Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *