Perzistencia dát v aplikáciách

perzistencia údajov pomocou AsyncStorage, SQLite, Realm, Firebase

What is Persistence About?

  • (slide)

  • moze to byt autentifikacny token alebo nastavenia pouzivatela

  • Trvácnosť údajov po reštarte aplikácie

    • údaje alebo nastavenia budú v stave, v ktorom používateľ aplikáciu opustil
  • Otázkou teda je, čo použiť na ukladanie údajov v aplikácii. A univerziálna odpoveď na túto otázku, je: To záleží.

    • od toho, či sa dáta majú nachádzať len na zariadení
    • či potrebujete server na ukladanie
    • či chcete dáta zdielať medzi viacerými aplikáciami
    • či majú byť vaše údaje k dispozícii aj bez internetu
    • či potrebujete údaje synchronizovať alebo nie

Data Persistence and Security

  • (slide) Ak teda chceme, aby údaje aplikácie prežili jej reštart, poprípade reštart celého zariadenia, musia byť niekde na zariadení fyzicky uložené. Otázkou je teda aj bezpečnosť uloženia týchto údajov, a teda:

    • prístup k týmto údajom priamo zo súborového systému
    • bezpečnosť uloženia samotných údajov, a hlavne
    • bezpečnosť uloženia citlivých údajov.
  • Persisted vs unpersisted — persisted data is written to the device’s memory, which lets the data be read by your app across application launches without having to do another network request to fetch it or asking the user to re-enter it. But this also can make that data more vulnerable to being accessed by attackers. Unpersisted data is never written to memory—so there’s no data to access!

Application Sandbox

  • (slide)

  • Mobilné platformy sa preto snažia o ochranu zdrojov aplikácie jej izolovaním od iných aplikácií. To znamená, že jedna aplikácia nemôže vojsť do priečinku súborového systému, ktorý patrí inej aplikácii. Vďaka tomu je možné aplikácie chrániť hlavne od škodlivých aplikácií, ktoré sa snažia dostať ku kritickým súborom, ako napr.

    • prístupové údaje k webovým službám, ktoré sú uložené v nastaveniach,
    • údaje uložené v databáze,
    • fotky, videá a zvukové nahrávky vytvorené kamerou a mikrofónom, alebo obecne
    • vytvorené/uložené zdroje aplikácie.
  • The Android platform takes advantage of the Linux user-based protection to identify and isolate app resources. This isolates apps from each other and protects apps and the system from malicious apps. To do this, Android assigns a unique user ID (UID) to each Android application and runs it in its own process.

  • problém - “rootnuté” zariadenia

Where are the Data

  • Všetky aplikácie majú údaje uložené v predvolenom priečinku s cestou /data/data/<package name>/. Predvolene sa tu budú nachádzať databázy aplikácie, nastavenia a pod. V prípade, že aplikácia potrebuje viac miesta, existuje špeciálny priečinok na SD karte s názvom Android/data/<package name>.

  • Organizácia priečinku s údajmi pre aplikáciu, môže vyzerať nasledovne:

    • databases/ - here go the app’s databases
    • lib/ - libraries and helpers for the app
    • files/ - other related files
    • shared_prefs/ - preferences and settings
    • cache/ - well, caches

AsyncStorage

  • (slide) Async Storage je jednoduché, aynchrónne, nešifrované, perzistentné úložisko typu slovník (key-value storage) pre React-Native aplikácie. Donedávna bol súčasťou react-native, dnes je už z neho samostatný projekt.

  • Async Storage is the React Native equivalent of Local Storage from the web.

  • Async Storage nie je zdieľaný medzi aplikáciami! Každá aplikácia má v rámci vlastného sandbox-u vlastný Async Storage a nemá prístup k údajom iných aplikácií.

Do Use Async Storage, When…

  • Používať Async Storage sa oplatí vtedy, keď:

    • Persisting non-sensitive data across app runs
    • Persisting Redux state
    • Persisting GraphQL state
    • Storing global app-wide variables

Don’t Use Async Storage for…

  • Vyhnite sa používaniu Async Storage, keď:

    • token storage
    • secrets

Installation

$ yarn add @react-native-async-storage/async-storage

Usage

  • Pred použitím treba importnúť:

    import AsyncStorage \
        from '@react-native-async-storage/async-storage';
  • (slide) Pre ukladanie alebo aktualizovanie (prepisovanie) údajov je možné použiť funkciu .setItem(key, value) napr. takto:

    async function storeData(key, value){
        try {
            await AsyncStorage.setItem(key, value);
        } catch (e) {
            // saving error
        }
    }
  • V prípade, že je potrebné uložiť objekt, spravíme z neho reťazec pomocou volania JSON.stringify():

    await AsyncStorage.setItem(key, JSON.stringify(value));
  • (slide) Na čítanie údajov je možné použiť funkciu .getItem(key), ktorá vráti:

    • promise, v ktorom sa nachádza uložená hodnota, alebo
    • null, ak hodnota pre daný kľúč nie je
    async function getData(key){
        try{
            return await AsyncStorage.getItem(key);
        }catch(e){
            // read error
        }
    }
  • Ako je vidieť, API je veľmi jednoduché a pripomína localStorage. Okrem uvedených funkcií ešte obsahuje:

    • .mergeItem(key, value) - Merges an existing value stored under key, with new value, assuming both values are stringified JSON.
    • .removeItem(key) - Removes item for a key.
    • .getAllKeys() - Returns all keys known to your App, for all callers, libraries, etc.
    • .multiGet(keys) - Fetches multiple key-value pairs for given array of keys in a batch.
    • .multiSet(keyValuePairs) - Stores multiple key-value pairs in a batch.
    • .clear() - Removes whole AsyncStorage data, for all clients, libraries, etc. You probably want to use removeItem or multiRemove to clear only your App’s keys.

Advanced

  • (slide) Na platforme Android je AsyncStorage nastavený na veľkosť 6MB. V prípade prekročenia tohto limitu dôjde k chybe database or disk is full.

  • This 6MB limit is a sane limit to protect the user from the app storing too much data in the database. This also protects the database from filling up the disk cache and becoming malformed (endTransaction() calls will throw an exception, not rollback, and leave the db malformed). You have to be aware of that risk when increasing the database size. We recommend to ensure that your app does not write more data to AsyncStorage than space is left on disk. Since AsyncStorage is based on SQLite on Android you also have to be aware of the SQLite limits.

  • V prípade, že potrebujete zvýšiť tento limit, upravte obsah súboru android/gradle.properties nastavením hodnoty voľby s názvom AsyncStorage_db_size_in_MB. Napr. zvýšenie limitu na 10MB bude vyzerať takto:

    AsyncStorage_db_size_in_MB=10

Data Security

  • Ako už bolo uvedené, AsyncStorage ponúka nešifrované perzistentné úložisko. Skúsme sa preto pozrieť, ako v skutočnosti vyzerá na disku zariadenia.

  • Začnime tým, že vylistujeme priečinok /data/data/ a pokúsime sa identifikovať názov balíčka našej aplikácie s využitím jej názvu, ktorý by sa v balíčku mal nachádzať (napr. com.persistence-1).

  • Po vojdení dovnútra v ňom uvidíme štruktúru priečinkov, ako bola spomenutá vyššie. V našom prípade vojdeme priamo do priečinku databases/, nakoľko pracujeme s databázou AsyncStorage.

  • Nájdeme tu súbor RKStorage, ktorý keď vylistujeme príkazom cat, tak sa bude veľmi ponášať na dump databázy. Dokonca v ňom nájdeme aj text, ktorý sme uložili.

  • Stiahneme súbor von zo zariadenia príkazom

    $ adb pull /data/data/com.persistence/databases/RKStorage
  • Ak nad ním spustíme príkaz file, tak sa dozvieme, o aký typ súboru ide:

    $ file RKStorage
    RKStorage: SQLite 3.x database, user version 1, last written 
    using SQLite version 3008010
  • Tým pádom je jasné, že sa jedná o štandardný databázový súbor SQLite, čo znamená, že nemáme problém s ním manipulovať pomocou príkazu sqlite3 ako na klientskom počítači, tak priamo v Android zariadení. Takže nám nerobí žiadny problém akokoľvek upravovať, či kradnúť údaje takto uložené:

    sqlite> .tables
    android_metadata      catalystLocalStorage
    
    sqlite> .schema
    CREATE TABLE android_metadata (locale TEXT);
    CREATE TABLE catalystLocalStorage (
        key TEXT PRIMARY KEY, 
        value TEXT NOT NULL);
    
    sqlite> select * from catalystLocalStorage;
    message|this is AsyncStorage
    
    sqlite> update catalystLocalStorage 
        set value='you have been hacked' 
        where key='message';
    
    sqlite> select * from catalystLocalStorage;
    message|you have been hacked

SQLite

  • Knižnicu SQLite netreba extra predstavovať, pretože vďaka svojim vlastnostiam sa s ňou dá stretnúť na mnohých miestach. Zo stránky projektu sa dozvieme základné vlastnosti:

    • SQLite je knižnica napísaná v jazyku C, ktorá poskytuje malý, rýchly, samostatný, vysoko dostupný, plnohodnotný SQL databázový engine.

    • SQLite je v súčasnosti najpoužívanejším databázovým enginom, pretože je zabudovaný priamo v mobilných zariadeniach, v mnohých počítačoch, resp. operačných systémoch a býva súčasťou mnohých aplikácií, ktoré denne používame.

  • Dôležité je povedať, že táto knižnica poskytuje serverless databázový engine.

  • Pre nás je zaujímavé, že SQLite je priamou súčasťou aj mobilnej platformy Android, kde je pomocou SDK možné priamo písať SQL príkazy. Existuje však mnoho rozširujúcich knižníc, ktoré pridávajú aj podporu ORM.

Realm

  • zástupca NoSQL databáz.