Sikring av iOS-data i hvilemodus Beskyttelse av brukerens data

Dette er den første av tre artikler om å sikre brukerdata i hvile. I dette innlegget begynner vi med det grunnleggende om å beskytte data på iOS, slik at du kan lære dagens beste praksis for å lagre data sikkert med Swift.

Enhver app som lagrer brukerens data, må ta vare på sikkerheten og personvernet til disse dataene. Som vi har sett med nylige brudd på data, kan det være svært alvorlige konsekvenser for ikke å beskytte brukerens lagrede data. I denne opplæringen lærer du noen gode fremgangsmåter for å beskytte brukerens data.

tillatelser

Før vi går inn i lagring av egendefinerte data, la oss se på data som kan deles av systemprogrammer. 

For mange iOS-versjoner har det blitt pålagt å be om apptillatelser til bruk og lagre noen av brukerens private data som er eksterne for appen, for eksempel når du lagrer og laster bilder til fotobiblioteket. Fra og med iOS 10 krever noen APIer som bruker brukerens private data, deg til å erklære at tilgangen på forhånd i prosjektets Info.plist fil. 

Det er mange rammer som kan få tilgang til data utenfor appen din, og hvert rammeverk har en tilsvarende personvernsnøkkel.

  • Bluetooth-deling: NSBluetoothPeripheralUsageDescription
  • Kalender: NSCalendarsUsageDescription
  • CallKit: NSVoIPUsageDescription
  • Kamera: NSCameraUsageDescription
  • Kontaktpersoner: NSContactsUsageDescription
  • Helse: NSHealthShareUsageDescription, NSHealthUpdateUsageDescription
  • HomeKit: NSHomeKitUsageDescription
  • Plassering: NSLocationAlwaysUsageDescription, NSLocationUsageDescription, NSLocationWhenInUseUsageDescription
  • Mediebibliotek: NSAppleMusicUsageDescription
  • mikrofon: NSMicrophoneUsageDescription
  • Bevegelse: NSMotionUsageDescription
  • Bilder: NSPhotoLibraryUsageDescription
  • påminnelser: NSRemindersUsageDescription
  • Talegjenkjenning: NSSpeechRecognitionUsageDescription
  • Sirikit: NSSiriUsageDescription
  • TV-leverandør: NSVideoSubscriberAccountUsageDescription

For eksempel er her en oppføring i Info.plist for å tillate appen din å laste inn og lagre verdier i kalenderen.

NSCalendarsUsageDescription Se og legg til hendelser i kalenderen din

Hvis en bruksbeskrivelse mangler når API forsøker å få tilgang til dataene, vil appen bare krasje.

Databeskyttelses-API

For alle brukerdata som er interne til appen, er det første du må tenke på om du må lagre informasjonen, og hvilke data som er avgjørende for appen. Hold så mye av viktige data i arbeidsminne i stedet for i lagringsplass. Dette er spesielt viktig for enhver personlig identifiserbar informasjon. 

Men hvis du må lagre data, er det en god ide å aktivere Apples databeskyttelse.

Databeskyttelse krypterer innholdet i appens container. Det er avhengig av at brukeren har et passord, og dermed er sikkerheten til kryptering knyttet til styrken på passordet. Med Touch ID og det oppgraderte filsystem kryptering introdusert i IOS 10.3, har databeskyttelsessystemet hatt mange forbedringer. Du kan aktivere databeskyttelse på tvers av appen ved å slå på Data beskyttelse i Capabilities delen av prosjektfilen din. Dette oppdaterer provisjonsprofilen din og rettighetsfilen for å inkludere datavernskapasiteten. Databeskyttelse tilbyr fire beskyttelsesnivåer, avbildet av FileProtectionType struktur:

  • ingen: ingen beskyttelse.
  • fullstendig: Data er ikke tilgjengelig mens enheten er låst. Dette er den anbefalte innstillingen for de fleste applikasjoner.
  • completeUnlessOpen: Data er tilgjengelig når enheten er låst opp, og fortsetter å være tilgjengelig til filen er stengt, selv om brukeren låser enheten. Filer kan også opprettes når enheten er låst. Dette alternativet er bra for når du må åpne en fil for å behandle og fortsette prosessen, selv om brukeren legger appen i bakgrunnen og låser enheten. Et eksempel kan være en jobb som laster opp en fil til en server.
  • completeUntilFirstUserAuthentication: Når enheten er oppstart, er filene ikke tilgjengelige før brukeren først låser opp enheten. Deretter er filer tilgjengelige selv når enheten er låst igjen. Alternativet er bra for filer som må åpnes en gang senere i bakgrunnen når enheten er låst, for eksempel under en bakgrunnsopptaksjobb.

fullstendig er standardnivået. For å unngå krasjer når koden prøver å få tilgang til data som er låst, kan du registrere deg for varsler via UIApplicationProtectedDataDidBecomeAvailable og UIApplicationProtectedDataWillBecomeUnavailable for å finne ut når dataene er tilgjengelige.

NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataDidBecomeAvailable, object: null, kø: OperationQueue.main, using: (melding) i // ...) NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataWillBecomeUtgjengelig, objekt: null, kø: OperationQueue.main, bruker: (melding) i // ...)

I tillegg kan du også sjekke UIApplication.shared.isProtectedDataAvailable flagg.

En viktig ting å huske på når du gjør det mulig å beskytte data er at hvis du bruker noen bakgrunnstjenester som bakgrunnsinnhenting, kan denne koden trenge tilgang til dataene dine i bakgrunnen når enheten er låst. For disse filene må du sette et beskyttelsesnivå på completeUntilFirstUserAuthentication. Du kan kontrollere beskyttelsesnivået for hver fil individuelt når du oppretter filer og kataloger ved hjelp av Filbehandler klasse.

la ok = FileManager.default.createFile (atPath: somePath, innhold: null, attributter: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) gjør prøv FileManager.default.createDirectory (atPath: somePath, medIntermediateDirectories: true, attributes: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) fange print (error)

Du kan også angi beskyttelsesnivået når du skriver til en fil. De Data objektet har en metode som kan skrive dataene til en fil, og du kan angi beskyttelsesnivået når du ringer denne metoden.

la data = Data.init () la filenURL = prøve! FileManager.default.url (for: .documentDirectory, i: .userDomainMask, appropriateFor: null, create: false) .appendingPathComponent ("somedata.dat") gjør prøv data.write (til: fileURL, alternativer: , .completeFileProtection])) fange print (error)

Du kan også angi beskyttelsesnivået når du konfigurerer Core Data-modellen.

la storeURL = docURL? .appendingPathComponent ("Model.sqlite") la butikkenOptions: [AnyHashable: Any] = [NSPersistentStoreFileProtectionKey: FileProtectionType.complete] gjør prøv koordinator.addPersistentStore (ofType: NSSQLiteStoreType, konfigurasjonsnavn: null, på: storeURL, alternativer : storeOptions) fange print (error)

Hvis du vil endre beskyttelsesnivået for en eksisterende fil, bruker du følgende:

gjør prøv FileManager.default.setAttributes ([FileAttributeKey.protectionKey: FileProtectionType.complete], ofItemAtPath: sti) ta utskrift (feil)

Dataintegritet

En del av å beskytte dine lagrede data inkluderer kontroll av integriteten. Det er god praksis å ikke blindt stole på dataene du laster fra lagring; Det kan ha vært et uhell eller skadelig endring. De NSSecureCoding protokollen kan brukes til å laste og lagre dataobjektene dine sikkert fra lagring. Det vil sørge for at objektene du laster inneholder de forventede dataene. Hvis du vil lagre ditt eget objekt, kan du overholde den sikre kodingsprotokollen i klassen din.

klasse Arkiv Eksempel: NSObject, NSSecureCoding var stringExample: String? ... 

Klassen må være arvet fra NSObject. Så, for å slå på sikker koding, overstyrer du supportsSecureCoding protokollmetode.

statisk var supportsSecureCoding: Bool get return true

Hvis det egendefinerte objektet ditt er deserialisert med init? (koder aDecoder: NSCoder), de decodeObject (Forkey :) Metoden skal erstattes med decodeObject (av: Forkey :), som sørger for at de riktige objekttypene pakkes ut fra lagring.

kreves init? (koder aDecoder: NSCoder) stringExample = aDecoder.decodeObject (av: NSString.self, forKey: "string_example") som String?  func kode (med aCoder: NSCoder) aCoder.encode (stringExample, forKey: "string_example")

Hvis du bruker NSKeyedUnarchiver For å laste data fra lagring, sørg for å angi dens requiresSecureCoding eiendom.

class func loadFromSavedData () -> ArchiveExample? var objekt: ArchiveExample? = Nil let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] som String la url = NSURL (fileURLWithPath: path) la filenURL = url.appendingPathComponent ("ArchiveExample.plist") hvis FileManager.default.fileExists (atPath : (filURL? .path!!) do let data = try Data.init (contentOf: fileURL!) la unarchiver = NSKeyedUnarchiver.init (forReadingWith: data) unarchiver.requiresSecureCoding = true object = unarchiver.decodeObject (av: ArchiveExample .self, forKey: NSKeyedArchiveRootObjectKey) unarchiver.finishDecoding () fange print (error) returobjekt; 

Ved å slå på sikker koding for lagringsoperasjoner, forhindrer du at du ved et uhell arkiverer et objekt som ikke overholder den sikre kodingsprotokollen.

func save () la path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] som String la url = NSURL (fileURLWithPath: path) la filenPath = url.appendingPathComponent ("ArchiveExample.plist") ?. = NSMutableData.init () la arkiver = NSKeyedArchiver.init (forWritingWith: data) archiver.requiresSecureCoding = ekte archiver.encode (selv, forKey: NSKeyedArchiveRootObjectKey) archiver.finishEncoding () la alternativer: NSData.WritingOptions = [.atomic, .completeFileProtection ] gjør prøv data.write (toFile: filePath !, alternativer: alternativer) ta print (error)

Bortenfor NSSecureCoding, Det er alltid godt å implementere dine egne data valideringskontroller ved å pakke ut arkiv eller motta vilkårlig innspilling generelt.

Data Trails

Siden iOS fortsetter å utvikle seg, er det alltid nye funksjoner som har potensial til å lekke lagrede data. Fra iOS 9 kan du få innholdet ditt indeksert i Spotlight-søk, og i iOS 10 kan du avsløre innholdet ditt til Widgets, for eksempel Widget i dag som vises på låseskjermbildet. Vær forsiktig hvis du vil avsløre innholdet ditt med disse nye funksjonene. Du kan ende opp med å dele mer enn du planla å!

IOS 10 legger også til en ny Handoff-funksjon, der dine kopierte data fra loddbord blir delt automatisk mellom enheter. Igjen, vær forsiktig så du ikke utsettes for sensitive data i tavlen til Handoff. Du kan gjøre dette ved å merke det sensitive innholdet som localOnly. Du kan også angi en utløpsdato og -tid for dataene.

la stringToCopy = "kopier meg til pasteboard" la pasteboard = UIPasteboard.general hvis #available (iOS 10, *) la i morgen = Dato (). addTimeInterval (60 * 60 * 24) pasteboard.setItems ([[kUTTypeUTF8PlainText as String: stringToCopy]], alternativer: [UIPasteboardOption.localOnly: true, UIPasteboardOption.expirationDate: i morgen]) ellers pasteboard.string = stringToCopy

Filer som er lagret i enhetens lagringsplass, kan automatisk sikkerhetskopieres, enten i iTunes eller i iCloud. Selv om sikkerhetskopier kan krypteres, er det en god ide å ekskludere sensitive filer som ikke engang trenger å forlate enheten. Dette kan gjøres ved å sette inn isExcludedFromBackup flagg på filen.

la banen: String = ... var url = URL (fileURLWithPath: sti) gjør var resourceValues ​​= URLResourceValues ​​() // eller hvis du først vil sjekke flagget: // var resourceValues ​​= prøv url.resourceValues ​​(forKeys: [.isExcludedFromBackupKey ]) resourceValues.isExcludedFromBackup = true; prøv url.setResourceValues ​​(resourceValues) fangst print (error)

Animasjonen som skjer når du legger en app inn i bakgrunnen, oppnås ved at iOS tar et skjermbilde av appen din, som den bruker til animasjonen. Når du ser på listen over åpne apper på appbryteren, brukes dette skjermbildet også der. Skjermbildet blir lagret på enheten. 

Det er en god ide å skjule alle visninger som avslører sensitive data, slik at dataene ikke blir tatt i skjermbildet. For å gjøre dette, sett opp et varsel når programmet går til bakgrunnen og sett den skjulte egenskapen for brukergrensesnittelementene du vil ekskludere. De vil bli skjult før iOS fanger skjermen. Så når du kommer til forgrunnen, kan du avdekke brukergrensesnittelementene.

NotificationCenter.default.addObserver (selector: #selector (didEnterBackground), navn: .UIApplicationDidEnterBackground, object: null) NotificationCenter.default.addObserver (selvvalg: #selector (willEnterForeground), navn: .UIApplicationWillEnterForeground, object: null)

Fjern meldingene dine når visningen forsvinner.

NotificationCenter.default.removeObserver (selv, navn: .UIApplicationDidEnterBackground, objekt: null) NotificationCenter.default.removeObserver (selv, navn: .UIApplicationWillEnterForeground, object: null)

Appen din har også et tastaturbuffer for tekstfelt som har automatisk korrigering aktivert. Tekst som brukeren skriver sammen med nylig lært ord, lagres i hurtigbufferen, slik at det er mulig å hente ulike ord som brukeren tidligere har angitt i søknaden din. Den eneste måten å deaktivere tastaturbufferen på, er å slå av alternativet for automatisk korrigering.

textField.autocorrectionType = UITextAutocorrectionType.no

Du bør merke passordfelter som sikker tekstoppføring. Sikker tekstfelt viser ikke passordet eller bruker tastaturbufferen.

textField.isSecureTextEntry = true

Feilsøkingslogger lagres i en fil og kan hentes for produksjonsbygg av appen din. Selv når du koder og feilsøker appen din, må du ikke logge på sensitiv informasjon som passord og nøkler til konsollen. Du kan glemme å fjerne den informasjonen fra loggene før du sender inn koden til appbutikken! Mens feilsøking er det sikrere å bruke et brytepunkt for å vise følsomme variabler.

Nettverksforbindelser kan også bli cachert til lagring. Mer informasjon om fjerning og deaktivering av nettverksbufferen finnes i artikkelen Sikring av kommunikasjon på iOS.

Ødelegge data

Du vet kanskje allerede at når en fil på en datamaskin slettes, blir selve filen ikke fjernet. bare referansen til filen er fjernet. For å faktisk fjerne filen, kan du overskrive filen med tilfeldige data før du fjerner den. 

Byttet til solid state-stasjoner har gjort det vanskelig å garantere at dataene er ødelagt, og den beste måten å slette data på, er åpen for debatt. Denne veiledningen vil imidlertid ikke være komplett uten et eksempel på hvordan du sletter data fra lagring. På grunn av noen andre debatter om Swift Optimizer, og fordi vi håper å garantere at hver byte av filen faktisk blir overskrevet, implementerer vi denne funksjonen i C. 

Implementeringen nedenfor kan gå inn i en .c-fil. Du må legge til funksjonsdefinisjonen eller filen som inneholder funksjonen i brooverhodet for å kunne bruke funksjonen fra Swift. Du kan da ønske å ringe denne funksjonen rett før steder der du bruker Filbehandler's removeFile metoder. Kanskje du kanskje vil implementere de beste metodene som beskrives i denne og de kommende opplæringsprogrammene i en appoppdatering. Du kan da tørke de tidligere ubeskyttede dataene under overføringen.

#importere  #importere  #importere  #importere  #importere  #importere  #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) // få filbeskrivelser int result = fstat (fileHandleInt, & stats); hvis (resultat == 0) switch (pass) // DOD 5220.22-M implementering sier at vi skriver over med tre passerer først med 10101010, 01010101 og deretter den tredje med tilfeldige datasak 1: // skriv over med 10101010 memset (charBuffer, 0x55, sizeof (charBuffer)); gå i stykker; tilfelle 2: // skriv over med 01010101 memset (charBuffer, 0xAA, sizeof (charBuffer)); gå i stykker; tilfelle 3: // skriv over med arc4random for (usignert 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; 

Konklusjon

I denne artikkelen har du lært om å sette inn tillatelser for dataene som appen din har tilgang til, samt hvordan du sikrer grunnleggende filbeskyttelse og integritet. Vi har også sett på noen måter at brukerdata kan lekkes ved et uhell fra appen din. Brukerne stoler på deg for å beskytte dataene sine. Følgende disse beste praksisene hjelper deg med å betale tilbake tilliten.

Mens du er her, sjekk ut noen av våre andre innlegg på IOS app utvikling!