Säkra iOS-data i vila Skydda användarens data

Detta är den första av tre artiklar om att säkra användardata i vila. I det här inlägget börjar vi med grunderna för att skydda data på IOS så att du kan lära dig de bästa metoderna för att lagra data säkert med Swift.

Varje app som sparar användarens data måste ta hand om säkerheten och integriteten för den dataen. Som vi har sett med de senaste dataöverträdelserna kan det vara mycket allvarliga konsekvenser för att inte skydda användarnas lagrade data. I den här handledningen lär du dig några bästa metoder för att skydda dina användares data.

Behörigheter

Innan vi får lagra dina anpassade data, låt oss ta en titt på data som kan delas av systemapps. 

För många iOS-versioner har det krävts att begära appbehörigheter att använda och lagra en del av användarens privata data som är externa till appen, till exempel när du sparar och laddar bilder till fotobiblioteket. Från och med iOS 10 måste alla API: er som är åtkomst till användarens privata data, förklara att åtkomst före tid i projektets Info.plist fil. 

Det finns många ramar som kan komma åt data utanför din app, och varje ram har en motsvarande sekretessnyckel.

  • Bluetooth-delning: NSBluetoothPeripheralUsageDescription
  • Kalender: NSCalendarsUsageDescription
  • CallKit: NSVoIPUsageDescription
  • Kamera: NSCameraUsageDescription
  • Kontakter: NSContactsUsageDescription
  • Hälsa: NSHealthShareUsageDescription, NSHealthUpdateUsageDescription
  • HomeKit: NSHomeKitUsageDescription
  • Plats: NSLocationAlwaysUsageDescription, NSLocationUsageDescription, NSLocationWhenInUseUsageDescription
  • Media bibliotek: NSAppleMusicUsageDescription
  • Mikrofon: NSMicrophoneUsageDescription
  • Rörelse: NSMotionUsageDescription
  • foton: NSPhotoLibraryUsageDescription
  • påminnelser: NSRemindersUsageDescription
  • Taligenkänning: NSSpeechRecognitionUsageDescription
  • Sirikit: NSSiriUsageDescription
  • TV-leverantör: NSVideoSubscriberAccountUsageDescription

Till exempel finns här en post i Info.plist så att din app kan ladda och lagra värden i kalendern.

NSCalendarsUsageDescription Visa och lägg till händelser i din kalender

Om en användningsbeskrivning saknas när API försöker komma åt data kommer appen helt enkelt att krascha.

Dataskydd API

För alla användardata som är interna till appen är det första att tänka på om du behöver lagra informationen och vilka data som är avgörande för appen. Håll så mycket av de väsentliga uppgifterna i arbetsminne i stället för i fillagring. Detta är särskilt viktigt för personligt identifierbar information. 

Men om du måste lagra data är det en bra idé att aktivera Apples dataskydd.

Dataskydd krypterar innehållet i din apps behållare. Det är beroende av att användaren har ett lösenord, och sålunda är krypteringens säkerhet kopplad till styrkan i lösenkoden. Med Touch ID och det uppgraderade filsystemet kryptering som introducerades i IOS 10.3 har datasäkerhetssystemet haft många förbättringar. Du kan aktivera dataskydd i din app genom att aktivera Dataskydd i Förmågor delen av din projektfil. Detta uppdaterar din provisioningprofil och rättighetsfil för att inkludera dataskyddskapaciteten. Dataskydd erbjuder fyra skyddsnivåer, avbildade av FileProtectionType strukturera:

  • ingen: Inget skydd.
  • komplett: Data är inte tillgänglig när enheten är låst. Det här är den rekommenderade inställningen för de flesta applikationer.
  • completeUnlessOpen: Data är tillgänglig när enheten är upplåst och fortsätter att vara tillgänglig tills filen är stängd, även om användaren låser enheten. Filer kan också skapas när enheten är låst. Det här alternativet är bra för när du behöver öppna en fil för att bearbeta och fortsätta processen även om användaren lägger appen i bakgrunden och låser enheten. Ett exempel kan vara ett jobb som laddar upp en fil till en server.
  • completeUntilFirstUserAuthentication: När enheten startas, är filer inte tillgängliga förrän användaren först låser upp enheten. Därefter finns filer tillgängliga även när enheten är låst igen. Alternativet är bra för filer som behöver nås senare i bakgrunden när enheten är låst, till exempel under ett bakgrundsuppdrag.

komplett är standardnivån. För att undvika kraschar när din kod försöker få åtkomst till data som är låst kan du registrera dig för meddelanden via UIApplicationProtectedDataDidBecomeAvailable och UIApplicationProtectedDataWillBecomeUnavailable att ta reda på när data är tillgängliga.

NotificationCenter.default.addObserver (forName: .UIApplicationProtectedDataDidBecomeAvailable, object: nil, kö: OperationQueue.main, using: (notification) in // ...) NotificationCenter.default.addObserver (forName: .UIAapplicationProtectedDataWillBecomeUtgänglig objekt: noll, kö: OperationQueue.main, using: (notification) in // ...)

Dessutom kan du också kontrollera UIApplication.shared.isProtectedDataAvailable flagga.

En viktig sak att komma ihåg när du aktiverar dataskydd är att om du använder några bakgrundstjänster som bakgrundshämtning, kan den koden behöva komma åt dina data i bakgrunden när enheten är låst. För dessa filer måste du ange en skyddsnivå på completeUntilFirstUserAuthentication. Du kan styra skyddsnivån för varje fil individuellt när du skapar filer och kataloger med hjälp av Filhanterare klass.

låt ok = FileManager.default.createFile (atPath: somePath, innehåll: nil, attribut: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) gör försök FileManager.default.createDirectory (atPath: somePath, medIntermediateDirectories: true, attributes: [FileAttributeKey.protectionKey.rawValue: FileProtectionType.complete]) fånga skriva ut (fel)

Du kan också ställa in skyddsnivån när du skriver till en fil. De Data objektet har en metod som kan skriva dess data till en fil och du kan ställa in skyddsnivån när du ringer den här metoden.

låt data = Data.init () låt fileURL = försök! FileManager.default.url (för: .documentDirectory, i: .userDomainMask, appropriateFor: nil, skapa: false) .appendingPathComponent ("somedata.dat") gör försök data.write (till: fileURL, options: , .completeFileProtection])) fånga skriv ut (fel)

Du kan också ställa in skyddsnivån när du ställer in din Core Data-modell.

låt storeURL = docURL? .appendingPathComponent ("Model.sqlite") låt storeOptions: [AnyHashable: Any] = [NSPersistentStoreFileProtectionKey: FileProtectionType.complete] gör försök koordinator.addPersistentStore (ofType: NSSQLiteStoreType, configurationName: nil, på: storeURL, alternativ : storeOptions) fånga skriv ut (fel)

Använd följande för att ändra skyddsnivån för en befintlig fil:

gör försök FileManager.default.setAttributes ([FileAttributeKey.protectionKey: FileProtectionType.complete], ofItemAtPath: sökvägen) fånga utskrift (fel)

Dataintegritet

En del av att skydda dina lagrade data inkluderar att kontrollera dess integritet. Det är bra att inte blinda lita på de data du laddar från lagring. Det kan ha varit oavsiktligt eller skadligt förändrat. De NSSecureCoding protokollet kan användas för att säkert ladda och spara dina dataobjekt från lagring. Det kommer att se till att föremålen du laddar innehåller de förväntade uppgifterna. Om du ska spara ditt eget objekt kan du överensstämma med det säkra kodningsprotokollet i din klass.

klass ArchiveExample: NSObject, NSSecureCoding var stringExample: String? ... 

Klassen måste vara ärvd från NSObject. Sedan, för att aktivera säker kodning, åsidosätta supportsSecureCoding protokollmetod.

static var supportsSecureCoding: Bool get return true

Om ditt anpassade objekt är deserialiserat med init? (kodare aDecoder: NSCoder), de decodeObject (forKey :) Metoden ska ersättas med decodeObject (av: forKey :), vilket säkerställer att de korrekta objekttyperna packas upp från lagring.

krävs init? (kodare aDecoder: NSCoder) stringExample = aDecoder.decodeObject (av: NSString.self, forKey: "string_example") som String?  func-kod (med aCoder: NSCoder) aCoder.encode (stringExample, forKey: "string_example")

Om du använder NSKeyedUnarchiver att ladda data från lagring, se till att ställa in dess requiresSecureCoding fast egendom.

klass func loadFromSavedData () -> ArchiveExample? var objekt: ArchiveExample? = Nil let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] som String låt url = NSURL (fileURLWithPath: path) släpp filenURL = url.appendingPathComponent ("ArchiveExample.plist") om FileManager.default.fileExists (atPath : (fileURL? path)!) do let data = försök Data.init (contentOf: fileURL!) låt unarchiver = NSKeyedUnarchiver.init (forReadingWith: data) unarchiver.requiresSecureCoding = true object = unarchiver.decodeObject (av: ArchiveExample .self, forKey: NSKeyedArchiveRootObjectKey) unarchiver.finishDecoding () fånga print (error) returnera objekt; 

Om du aktiverar säker kodning för dina sparningsoperationer kommer du att förhindra att du oavsiktligt arkiverar ett objekt som inte följer det säkra kodningsprotokollet.

func save () let path = NSSearchPathForDirectoriesInDomains (.documentDirectory, .userDomainMask, true) [0] som String låt url = NSURL (fileURLWithPath: path) släpp filePath = url.appendingPathComponent ("ArchiveExample.plist")? = NSMutableData.init () Låt archiver = NSKeyedArchiver.init (forWritingWith: data) archiver.requiresSecureCoding = sant archiver.encode (själv, förKey: NSKeyedArchiveRootObjectKey) archiver.finishEncoding () Låt alternativ: NSData.WritingOptions = [.atomic, .completeFileProtection ] gör försök data.write (toFile: filePath !, options: options) fånga skriv ut (fel)

Bortom NSSecureCoding, Det är alltid bra att genomföra dina egna data valideringskontroller vid utpakning av arkiv eller mottagning av godtycklig inmatning i allmänhet.

Data spår

Eftersom iOS fortsätter att utvecklas finns det alltid nya funktioner som kan läcka lagrade data. Från och med iOS 9 kan du ha innehållet indexerat i Spotlight-sökningen, och i IOS 10 kan du avslöja ditt innehåll till Widgets, som till exempel Today Widget som visas på låsskärmen. Var försiktig om du vill avslöja ditt innehåll med dessa nya funktioner. Du kanske slutar dela mer än du planerade att!

IOS 10 lägger också till en ny Handoff-funktion där dina kopierade kartongdata delas automatiskt mellan enheter. Var försiktig så att du inte exponerar känsliga data i skivbordet till Handoff. Du kan göra detta genom att markera det känsliga innehållet som localonly. Du kan också ange ett utgångsdatum och tid för data.

låt stringToCopy = "kopiera mig till pasteboard" låt pasteboard = UIPasteboard.general if # available (iOS 10, *) låt imorgon = Datum (). addTimeInterval (60 * 60 * 24) pasteboard.setItems ([[kUTTypeUTF8PlainText as String: stringToCopy]], alternativ: [UIPasteboardOption.localOnly: true, UIPasteboardOption.expirationDate: imorgon]) annars pasteboard.string = stringToCopy

Filer som sparas i enhetens lagring kan automatiskt säkerhetskopieras, antingen i iTunes eller i iCloud. Även om säkerhetskopieringar kan krypteras är det en bra idé att utesluta känsliga filer som inte ens behöver lämna enheten. Detta kan göras genom att ställa in isExcludedFromBackup flagga på filen.

låt sökväg: String = ... var url = URL (fileURLWithPath: path) gör var resourceValues ​​= URLResourceValues ​​() // eller om du vill först kontrollera flaggan: // var resourceValues ​​= prova url.resourceValues ​​(forKeys: [.isExcludedFromBackupKey ]) resourceValues.isExcludedFromBackup = true; prova url.setResourceValues ​​(resourceValues) fånga print (error)

Animationen som händer när du lägger en app i bakgrunden uppnås genom att iOS tar en skärmdump av din app som den sedan använder för animeringen. När du tittar på listan med öppna appar på appomkopplaren används denna skärmdump också där. Skärmdumpen lagras på enheten. 

Det är en bra idé att dölja alla synpunkter som visar känslig data så att data inte fångas i skärmdumpen. För att göra detta, skapa en anmälan när programmet går till bakgrunden och ange den dolda egenskapen för de gränssnitt som du vill utesluta. De kommer att döljas innan IOS fångar skärmen. Sedan när du kommer till förgrunden kan du ta bort användargränssnittet.

NotificationCenter.default.addObserver (self selector: #selector (didEnterBackground), namn: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.addObserver (self selector: #selector (willEnterForeground), namn: .UIApplicationWillEnterForeground, object: nil)

Ta bort dina meddelanden när vyn försvinner.

NotificationCenter.default.removeObserver (själv, namn: .UIApplicationDidEnterBackground, object: nil) NotificationCenter.default.removeObserver (själv, namn: .UIApplicationWillEnterForeground, object: nil)

Din app har också ett cacheminne för textfält som har autokorrigering aktiverat. Text som användaren skriver tillsammans med nylärda ord lagras i cachen så att det går att hämta olika ord som användaren tidigare har angett i din ansökan. Det enda sättet att inaktivera tangentbordets cache är att stänga av alternativet för automatisk korrigering.

textField.autocorrectionType = UITextAutocorrectionType.no

Du bör markera lösenordsfält som säker textinmatning. Säkra textfält visar inte lösenordet eller använder tangentbordets cache.

textField.isSecureTextEntry = true

Felsökningsloggar sparas i en fil och kan hämtas för produktionsbyggnader av din app. Även när du kodar och felsöker din app, se till att du inte loggar in känslig information som lösenord och nycklar till konsolen. Du kanske glömmer att ta bort den informationen från loggarna innan du skickar in din kod till appbutiken! Medan felsökning är det säkrare istället att använda en brytpunkt för att se känsliga variabler.

Nätverksanslutningar kan också bli cachade till lagring. Mer information om hur du tar bort och inaktiverar nätverkscachen finns i artikeln Säkra kommunikation på iOS.

Förstöra data

Du kanske redan vet att när en fil på en dator raderas, är filen ofta inte borttagen. Endast referensen för filen tas bort. För att faktiskt ta bort filen kan du skriva över filen med slumpmässiga data innan du tar bort den. 

Växeln till solid state-enheter har gjort det svårt att garantera att data har förstörts, och det bästa sättet att säkert radera data är öppen för debatt. Denna handledning skulle emellertid inte vara komplett utan ett exempel på hur man torkar data från lagring. På grund av några andra debatter om Swift Optimizer, och för att vi hoppas kunna garantera att varje bit av filen faktiskt skrivs över, implementerar vi den här funktionen i C. 

Genomförandet nedan kan gå in i en .c-fil. Du måste lägga till funktionsdefinitionen eller filen som innehåller funktionen i ditt broschyr för att använda funktionen från Swift. Du kan då vilja ringa denna funktion direkt före platser där du använder Filhanterare's ta bort fil metoder. Kanske kanske du vill genomföra de bästa metoderna som beskrivs i detta och de kommande handledningarna i en appuppdatering. Du kan sedan torka bort de tidigare oskyddade data under migrering.

#importera  #importera  #importera  #importera  #importera  #importera  #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å filbeskrivningar int result = fstat (fileHandleInt, & stats); om (resultat == 0) switch (passera) // DOD 5220.22-M-implementering anger att vi skriver över med tre passerar först med 10101010, 01010101 och sedan den tredje med slumpmässigt datasak 1: // skriv över med 10101010 memset (charBuffer, 0x55, sizeof (charBuffer)); ha sönder; fall 2: // skriv över med 01010101 memset (charBuffer, 0xAA, sizeof (charBuffer)); ha sönder; fall 3: // skriv över med arc4random för (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; 

Slutsats

I den här artikeln har du lärt dig om att ställa in behörigheter för de data som din app har tillgång till, samt hur man säkerställer grundläggande filskydd och integritet. Vi tittade också på vissa sätt att användardata kan läckas av misstag från din app. Dina användare lita på dig för att skydda deras data. Att följa dessa bästa metoder hjälper dig att betala tillbaka det förtroendet.

Medan du är här, kolla in några av våra andra inlägg i IOS App Development!