Acesta este primul din cele trei articole despre securizarea datelor de utilizator în repaus. În acest post, vom începe cu elementele de bază ale protejării datelor de pe iOS, astfel încât să puteți afla cele mai bune practici curente pentru stocarea sigură a datelor cu Swift.
Orice aplicație care salvează datele utilizatorului trebuie să se ocupe de securitatea și confidențialitatea datelor respective. Așa cum am văzut cu încălcări recente ale datelor, pot exista consecințe foarte grave pentru a nu proteja datele stocate de utilizatori. În acest tutorial, veți afla câteva bune practici pentru protejarea datelor utilizatorilor.
Înainte de a intra în stocarea datelor personalizate, să aruncăm o privire asupra datelor care pot fi distribuite de aplicațiile de sistem.
Pentru multe versiuni iOS, a fost cerut să solicite permisiuni de aplicații pentru a utiliza și stoca unele date private ale utilizatorului care sunt externe aplicației, cum ar fi atunci când salvați și încărcați imagini în biblioteca foto. Începând cu iOS 10, orice API-uri care accesează datele private ale utilizatorului necesită să declarați că accesul în timp util în proiectul dvs. info.plist fişier.
Există multe cadre care pot accesa date în afara aplicației dvs. și fiecare cadru are o cheie de confidențialitate corespunzătoare.
NSBluetoothPeripheralUsageDescription
NSCalendarsUsageDescription
NSVoIPUsageDescription
NSCameraUsageDescription
NSContactsUsageDescription
NSHealthShareUsageDescription
, NSHealthUpdateUsageDescription
NSHomeKitUsageDescription
NSLocationAlwaysUsageDescription
, NSLocationUsageDescription
, NSLocationWhenInUseUsageDescription
NSAppleMusicUsageDescription
NSMicrophoneUsageDescription
NSMotionUsageDescription
NSPhotoLibraryUsageDescription
NSRemindersUsageDescription
NSSpeechRecognitionUsageDescription
NSSiriUsageDescription
NSVideoSubscriberAccountUsageDescription
De exemplu, aici este o intrare în info.plist pentru a permite aplicației dvs. să încarce și să stocheze valori în calendar.
NSCalendarsUsageDescription Vizualizați și adăugați evenimente în calendar
Dacă lipsește o descriere de utilizare atunci când API încearcă să acceseze datele, aplicația se va prăbuși.
Pentru orice date de utilizator care sunt interne ale aplicației, primul lucru pe care trebuie să-l gândiți este dacă trebuie să stocați informațiile și ce date sunt esențiale pentru aplicație. Păstrați cât mai mult din aceste date esențiale în memoria de lucru în loc de stocare în fișiere. Acest lucru este important în special pentru orice informație care poate fi identificată personal.
Dar, dacă trebuie să stocați date, este o idee bună să activați protecția datelor Apple.
Protecția datelor criptează conținutul containerului aplicației. Se bazează pe faptul că utilizatorul are un cod de trecere și astfel securitatea criptării este legată de puterea parolei. Cu ID-ul Touch și cu criptarea actualizată a sistemului de fișiere introdusă în iOS 10.3, sistemul de protecție a datelor a avut multe îmbunătățiri. Puteți activa protecția datelor în aplicația dvs. pornind Protejarea datelor în Capacități secțiunea din fișierul dvs. de proiect. Aceasta actualizează profilul dvs. de furnizare și fișierul de drepturi pentru a include capacitatea de protecție a datelor. Protecția datelor oferă patru niveluri de protecție, descrise de FileProtectionType
structura:
nici unul
: nici o protecție.complet
: datele nu sunt accesibile în timp ce dispozitivul este blocat. Aceasta este setarea recomandată pentru majoritatea aplicațiilor.completeUnlessOpen
: datele sunt accesibile atunci când dispozitivul este deblocat și continuă să fie accesibil până când fișierul este închis, chiar dacă utilizatorul blochează dispozitivul. De asemenea, pot fi create fișiere atunci când dispozitivul este blocat. Această opțiune este utilă atunci când trebuie să deschideți un fișier pentru procesare și să continuați procesul chiar dacă utilizatorul pune aplicația în fundal și blochează dispozitivul. Un exemplu poate fi o lucrare care încarcă un fișier pe un server.completeUntilFirstUserAuthentication
: când dispozitivul este pornit, fișierele nu sunt accesibile până când utilizatorul deblochează mai întâi dispozitivul. După aceea, fișierele sunt disponibile chiar și atunci când dispozitivul este blocat din nou. Opțiunea este bună pentru fișierele care trebuie să fie accesate mai târziu în fundal atunci când dispozitivul este blocat, cum ar fi în timpul unei preluări de fundal.complet
este nivelul implicit. Pentru a evita accidentele atunci când codul dvs. încearcă să acceseze date care sunt blocate, vă puteți înregistra pentru notificări prin intermediul UIApplicationProtectedDataDidBecomeAvailable
și UIApplicationProtectedDataWillBecomeUnavailable
pentru a afla când datele sunt disponibile.
NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataDidBecomeAvailable, obiect: nil, queue: OperationQueue.main, folosind: (notification) în // ...) NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataWillBecomeUnavailable, object: nil, queue: OperationQueue.main, utilizând: (notificare) în // ...)
În plus, puteți verifica și UIApplication.shared.isProtectedDataAvailable
steag.
Un lucru important pe care trebuie să-l aveți în vedere atunci când activați protecția datelor este că dacă utilizați orice servicii de fundal, cum ar fi preluarea de fundal, acel cod poate avea nevoie de acces la datele dvs. în fundal atunci când dispozitivul este blocat. Pentru aceste fișiere, va trebui să setați un nivel de protecție de completeUntilFirstUserAuthentication
. Puteți controla nivelul de protecție al fiecărui fișier în mod individual atunci când creați fișiere și directoare folosind Manager de fișiere
clasă.
permiteți fișierului FileManager.default.createFile (atPath: somePath, content: nil, atribute: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) try FileManager.default.createDirectory (atPath: somePath, withIntermediateDirectories: true, atribute: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) captura print (eroare)
De asemenea, puteți seta nivelul de protecție atunci când scrieți la un fișier. Date
obiectul are o metodă care își poate scrie datele într-un fișier și puteți seta nivelul de protecție atunci când apelați această metodă.
lasati data = Data.init () lasati fileURL = try! FileManager.default.url (pentru: .documentDirectory, în: .userDomainMask, appropriateFor: nil, create: false) .appendingPathComponent ("somedata.dat") nu try data.write (la: fileURL, opțiuni: , .completeFileProtecție])) captura print (eroare)
De asemenea, puteți seta nivelul de protecție atunci când vă configurați modelul Core Data.
permiteți storeURL = docURL? .appendingPathComponent ("Model.sqlite") lăsați storeOptions: [AnyHashable: Any] = [NSPersistentStoreFileProtectionKey: FileProtectionType.complete] try coordinator.addPersistentStore (ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options : storeOptions) captura print (eroare)
Pentru a modifica nivelul de protecție al unui fișier existent, utilizați următoarele:
încercați FileManager.default.setAttributes ([FileAttributeKey.protectionKey: FileProtectionType.complete], dinItemAtPath: cale) captură print (error)
O parte a protejării datelor stocate include verificarea integrității. Este o practică bună să nu aveți încredere orb în datele pe care le încărcați din spațiul de stocare; poate că a fost modificată accidental sau rău. NSSecureCoding
protocolul poate fi folosit pentru a încărca în siguranță și pentru a salva obiectele de date din spațiul de stocare. Se va asigura că obiectele încărcate conțin datele așteptate. Dacă vă veți salva propriul obiect, puteți să vă conformați protocolului securizat de codare din interiorul clasei dvs..
Arhiva clasaExemplu: NSObject, NSSecureCoding var stringExemplu: String? ...
Clasa trebuie moștenită NSObject
. Apoi, pentru a activa codarea securizată, suprascrieți supportsSecureCoding
metoda protocolului.
static var susțineSecureCoding: Bool get return true
Dacă obiectul dvs. obișnuit este deserializat init? (coder aDecoder: NSCoder)
, decodeObject (forKey :)
metoda trebuie înlocuită cu decodeObject (de: forKey :)
, care vă asigură că tipurile de obiecte corecte sunt despachetate din spațiul de stocare.
(Coder aDecoder: NSCoder) stringExample = aDecoder.decodeObject (de: NSString.self, pentruKey: "string_example") ca String? func encode (cu aCoder: NSCoder) aCoder.encode (stringExample, pentruKey: "string_example")
Dacă utilizați NSKeyedUnarchiver
pentru a încărca datele din spațiul de stocare, asigurați-vă că ați setat requiresSecureCoding
proprietate.
class func loadFromSavedData () -> ArhivaExemplu? var object: ArchiveExample? = nil permite cale = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] ca String let url = NSURL (fileURLWithPath: path) permite fileURL = url.appendingPathComponent ("ArchiveExample.plist") dacă FileManager.default.fileExists : (fișierURL? .path)!) do lasă data = încercați Data.init (contentsOf: fileURL!) unarchiver = NSKeyedUnarchiver.init (pentruReadingWith: data) unarchiver.requiresSecureCoding = true object = unarchiver.decodeObject .self, forKey: NSKeyedArchiveRootObjectKey) unarchiver.finishDecoding () captura print (error) return obiect;
Activarea codării securizate pentru operațiile de salvare vă va împiedica să arhivați accidental un obiect care nu aderă la protocolul de codificare securizat.
funcția save () let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] ca String let url = NSURL (fileURLWithPath: path) permite calea filePath = url.appendingPathComponent ("ArchiveExample.plist")? = NSMutableData.init () permite arhivatorului = NSKeyedArchiver.init (forWritingWith: date) archiver.requiresSecureCoding = true archiver.encode (auto, forKey: NSKeyedArchiveRootObjectKey) archiver.finishEncoding () permite optiuni: NSData.WritingOptions = [.atomic, .completeFileProtection ] încercați data.write (toFile: filePath !, opțiuni: opțiuni) captură print (eroare)
Dincolo NSSecureCoding
, este întotdeauna bine să implementați propriile verificări de validare a datelor atunci când despachetați orice arhivă sau primiți o intrare arbitrară în general.
Pe măsură ce iOS continuă să evolueze, există întotdeauna noi caracteristici care au potențialul de a scurge datele stocate. Începând cu versiunea iOS 9, conținutul dvs. poate fi indexat în căutarea Spotlight, iar în iOS 10 puteți expune conținutul dvs. la Widgeturi, cum ar fi Widget-ul de astăzi care apare pe ecranul de blocare. Aveți grijă dacă doriți să vă expuneți conținutul cu aceste funcții noi. S-ar putea să vă împărțiți mai mult decât ați plănuit!
iOS 10 adaugă, de asemenea, o nouă caracteristică Handoff, în care datele copiate ale cartonului sunt partajate automat între dispozitive. Din nou, aveți grijă să nu expuneți niciun fel de date delicate din carton la Handoff. Puteți face acest lucru prin marcarea conținutului sensibil ca localOnly
. De asemenea, puteți seta o dată și o oră de expirare pentru date.
lasati stringToCopy = "copiati-ma in pasteboard" lasi pasteboard = UIPasteboard.general daca #available (iOS 10, *) letorrow = Date () stringToCopy]], opțiuni: [UIPasteboardOption.localOnly: true, UIPasteboardOption.expirationDate: mâine]) altceva pasteboard.string = stringToCopy
Fișierele salvate pe spațiul de stocare al dispozitivului pot primi automat backup, fie în iTunes, fie în iCloud. Chiar dacă backup-urile pot fi criptate, este o idee bună să excludeți orice fișiere sensibile care nu trebuie nici măcar să părăsească dispozitivul. Acest lucru se poate face prin setarea isExcludedFromBackup
în dosar.
permiteți calea: String = ... var url = URL (fileURLWithPath: path) nu var resourceValues = URLResourceValues () // sau dacă doriți să verificați mai întâi flagul: // var resourceValues = try url.resourceValues (forKeys: [.isExcludedFromBackupKey ]) resourceValues.isExcludedFromBackup = true; încercați url.setResourceValues (resourceValues) captura print (error)
Animația care se întâmplă atunci când se pune o aplicație în fundal este realizată de iOS făcând o captură de ecran a aplicației pe care o folosește pentru animație. Când te uiți la lista de aplicații deschise pe switch-ul de aplicații, această captură de ecran este folosită și acolo. Imaginea de ecran este stocată pe dispozitiv.
Este o idee bună să ascundeți orice vizualizare care dezvăluie date sensibile, astfel încât datele să nu fie capturate în captura de ecran. Pentru a face acest lucru, configurați o notificare atunci când aplicația merge în fundal și setați proprietatea ascunsă pentru elementele UI pe care doriți să le excludeți. Acestea vor fi ascunse înainte ca iOS să surprindă ecranul. Apoi, când veniți în prim-plan, puteți dezvălui elementele UI.
NotificareCenter.default.addObserver (selector: #selector (didEnterBackground), nume: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.addObserver (auto, selector: #selector (willEnterForeground), name: .UIApplicationWillEnterForeground, object:
Eliminați notificările atunci când vizualizarea dispare.
NotificationCenter.default.removeObserver (sine, nume: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.removeObserver (sine, nume: .UIApplicationWillEnterForeground, object: nil)
Aplicația are, de asemenea, o memorie cache pentru câmpurile de text care au activat corect corectarea automată. Textul introdus de utilizator, împreună cu cuvintele recent învățate, sunt stocate în memoria cache, astfel încât să poată fi preluate diverse cuvinte pe care utilizatorul le-a introdus anterior în aplicație. Singura modalitate de a dezactiva memoria cache a tastaturii este să dezactivați opțiunea de auto-corectare.
textField.autocorrectionType = UITextAutocorrectionType.no
Ar trebui să marcați câmpurile de parolă ca intrări de text securizate. Câmpurile de siguranță securizate nu afișează parola sau nu utilizează memoria cache a tastaturii.
textField.isSecureTextEntry = adevărat
Jurnalele de depanare sunt salvate într-un fișier și pot fi preluate pentru construirea de producție a aplicației dvs. Chiar și atunci când codificați și depanați aplicația, asigurați-vă că nu conectezi la consola informații sensibile precum parole și chei. S-ar putea să uitați să eliminați aceste informații din jurnale înainte de a trimite codul dvs. la magazinul de aplicații! În timp ce depanați, este mai sigur să utilizați un breakpoint pentru a vizualiza variabilele sensibile.
Conexiunile de rețea pot fi stocate în memoria cache. Mai multe informații despre eliminarea și dezactivarea cache-ului de rețea pot fi găsite în articolul Securizarea comunicațiilor pe iOS.
Este posibil să știți deja că atunci când un fișier de pe un computer este șters, deseori fișierul în sine nu este eliminat; numai referința pentru fișier este eliminată. Pentru a elimina efectiv fișierul, puteți suprascrie fișierul cu date aleatorii înainte de ao elimina.
Comutarea la unitățile de stocare în stare solidă a făcut dificilă garantarea distrugerii datelor și cel mai bun mod de a șterge în siguranță datele este deschis dezbaterii. Cu toate acestea, acest tutorial nu ar fi completat fără un exemplu de ștergere a datelor din spațiul de stocare. Din cauza altor dezbateri despre sistemul de optimizare Swift și pentru că sperăm să garantăm că fiecare octet al fișierului este de fapt suprascris, implementăm această funcție în C.
Implementarea de mai jos poate merge în interiorul unui fișier .c. Va trebui să adăugați definiția funcției sau fișierul care conține funcția în antetul dvs. de legătură pentru a utiliza funcția de la Swift. Apoi, puteți dori să apelați această funcție chiar înainte de locurile în care utilizați Manager de fișiere
„s sterge fisier
metode. Poate că ați putea dori să implementați cele mai bune practici descrise în această și tutoriale viitoare pe o actualizare a aplicației. Apoi, puteți șterge datele anterioare neprotejate în timpul migrării.
#import#import #import #import #import #import #define MY_MIN (a, b) (((a) < (b)) ? (a) : (b)) int SecureWipeFile(const char *filePath) int lastStatus = -1; for (int pass = 1; pass < 4; pass++) //setup local vars int fileHandleInt = open(filePath, O_RDWR); struct stat stats; unsigned char charBuffer[1024]; //if can open file if (fileHandleInt >= 0) // obține descriptorii de fișiere int result = fstat (fileHandleInt, & stats); dacă (rezultat == 0) switch (pass) // DOD 5220.22-M prevede că scriem cu trei treceri mai întâi cu 10101010, 01010101 și apoi cu al treilea caz cu date aleatorii 1: // scrieți peste cu 10101010 memset (charBuffer, 0x55, sizeof (charBuffer)); pauză; cazul 2: // scrieți cu 01010101 memset (charBuffer, 0xAA, sizeof (charBuffer)); pauză; cazul 3: // scrie peste cu arc4random pentru (unsigned long i = 0; i < sizeof(charBuffer); ++i) charBuffer[i] = arc4random() % 255; break; default: //at least write over with random data for (unsigned long i = 0; i < sizeof(charBuffer); ++i) charBuffer[i] = arc4random() % 255; break; //get file size in bytes off_t fileSizeInBytes = stats.st_size; //rewrite every byte of the file ssize_t numberOfBytesWritten; for ( ; fileSizeInBytes; fileSizeInBytes -= numberOfBytesWritten) //write bytes from the buffer into the file numberOfBytesWritten = write(fileHandleInt, charBuffer, MY_MIN((size_t)fileSizeInBytes, sizeof(charBuffer))); //close the file lastStatus = close(fileHandleInt); return lastStatus;
În acest articol, ați aflat despre setarea permisiunilor pentru datele la care aplicația dvs. are acces, precum și despre modul în care puteți asigura protecția și integritatea fișierului de bază. De asemenea, am analizat în unele moduri că datele de utilizator ar putea fi scoase accidental din aplicația dvs. Utilizatorii dvs. au încredere în dvs. pentru a-și proteja datele. Urmărirea acestor bune practici vă va ajuta să vă răsplătiți cu încredere.
În timp ce sunteți aici, verificați câteva dintre celelalte postări ale noastre privind dezvoltarea aplicațiilor iOS!