Data Persistence
perzistencia údajov pomocou AsyncStorage, SQLite, Realm,
What is Persistence About?
(slide)
Trvácnosť údajov po reštarte aplikácie
- údaje alebo nastavenia budú v stave, v ktorom používateľ aplikáciu opustil
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!
Upozornenie
Never store sensitive API keys in your app code. Anything included in your code could be accessed in plain text by anyone inspecting the app bundle. Tools like react-native-dotenv and react-native-config are great for adding environment-specific variables like API endpoints, but they should not be confused with server-side environment variables, which can often contain secrets and api keys.
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ázvomAndroid/data/<package name>
.Upozornenie
Na SD kartu môžu svoje údaje ukladať všetky aplikácie. Na karte však nie sú žiadne reštrikcie pre ukladanie údajov! To môže viesť jednak k zmätku v názvosloví a organizácii súborov a priečinkov, ako aj k nebezpečenstvu získania údajov takto uložených. Rovnaký problém môže nastať aj v prípade root aplikácií, ale na úrovni celého zariadenia.
Organizácia priečinku s údajmi pre aplikáciu, môže vyzerať nasledovne:
databases/
- here go the app’s databaseslib/
- libraries and helpers for the appfiles/
- other related filesshared_prefs/
- preferences and settingscache/
- 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.Poznámka
Async Storage umožňuje ukladať len reťazce (údaje typu
string
). Takže ak chceme ukladať aj iné typy údajov alebo obecne objekty, musíme ich predtým serializovať. Pre serializáciu do JSON-u je možné pri ukladaní použiťJSON.stringify()
a pri načítavaní zasaJSON.parse()
.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
Poznámka
Pre staršie verzie ReactNative bude potrebné aj linkovať:
$ react-native link \
@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 akey
..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 chybedatabase 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ázvomAsyncStorage_db_size_in_MB
. Napr. zvýšenie limitu na 10MB bude vyzerať takto:=10 AsyncStorage_db_size_in_MB
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ázouAsyncStorage
.Nájdeme tu súbor
RKStorage
, ktorý keď vylistujeme príkazomcat
, 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é:> .tables sqlite android_metadata catalystLocalStorage > .schema sqliteCREATE TABLE android_metadata (locale TEXT); CREATE TABLE catalystLocalStorage ( key TEXT PRIMARY KEY, value TEXT NOT NULL); > select * from catalystLocalStorage; sqliteis AsyncStorage message|this > update catalystLocalStorage sqliteset value='you have been hacked' where key='message'; > select * from catalystLocalStorage; sqlite 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.