Sikring og kryptering av data på iOS

Enten du lager et mobilprogram eller en webtjeneste, er det viktig å holde følsomme data sikre, og sikkerheten er blitt et viktig aspekt ved hvert programvareprodukt. I denne veiledningen vil jeg vise deg hvordan du trygt lagrer brukeropplysningene ved hjelp av programmets nøkkelring, og vi vil se på kryptering og dekryptering av brukerdata ved hjelp av et tredjepartsbibliotek.


Introduksjon

I denne veiledningen vil jeg lære deg hvordan du sikrer sensitive data på iOS-plattformen. Følsomme data kan være brukerens konto legitimasjon eller kredittkort detaljer. Datatypen er ikke så viktig. I denne opplæringen bruker vi iOS nøkkelring og symmetrisk kryptering for å lagre brukerens data sikkert. Før vi kommer inn i nitty-gritty detaljer, vil jeg gjerne gi deg en oversikt over hva vi skal gjøre i denne opplæringen.

Selv om denne opplæringen fokuserer på iOS, kan konseptene og teknikkene også brukes på OS X.

iOS nøkkelring

På IOS og OS X er et nøkkelring en kryptert beholder for lagring av passord og annen data som må sikres. På OS X er det mulig å begrense nøkkelring tilgang til bestemte brukere eller applikasjoner. På iOS har hver applikasjon imidlertid et eget nøkkelring som kun programmet har tilgang til. Dette sikrer at dataene som er lagret i nøkkelringen, er trygge og utilgjengelige av tredjeparter.

Husk at nøkkelringen bare skal brukes til lagring av små biter av data, for eksempel passord. Med denne artikkelen håper jeg å overbevise deg om verdien av å bruke nøkkelringen på iOS og OS X i stedet for for eksempel applikasjonens standarddatabase, som lagrer dataene i vanlig tekst uten noen form for sikkerhet.

På iOS kan et program bruke nøkkelringen gjennom Nøkkelringstjenester API. API gir en rekke funksjoner for å manipulere dataene som er lagret i programmets nøkkelring. Ta en titt på funksjonene som er tilgjengelige på iOS.

  • SecItemAdd Denne funksjonen brukes til å legge til et element i programmets nøkkelring.
  • SecItemCopyMatching Du bruker denne funksjonen til å finne et nøkkelringelement som eies av søknaden.
  • SecItemDelete Som navnet tilsier, kan denne funksjonen brukes til å fjerne et element fra programmets nøkkelring.
  • SecItemUpdate Bruk denne funksjonen hvis du trenger å oppdatere et element i programmets nøkkelring.

De Nøkkelringstjenester API er en C API, men jeg håper det ikke hindrer deg i å bruke den. Hver av de ovennevnte funksjonene godtar en ordbok (CFDictionaryRef), som inneholder et element klasse nøkkelverdier par og valgfrie attributt nøkkelverdier par. Den nøyaktige betydningen og hensikten med hver enkelt blir klar når vi begynner å bruke API-en i et eksempel.


Kryptering og dekryptering

Når du diskuterer kryptering, hører du vanligvis om to typer kryptering, symmetrisk og asymmetrisk kryptering. Symmetrisk kryptering bruker på den ene siden en felles nøkkel for kryptering og dekryptering av data. Asymmetrisk kryptering, derimot, bruker en nøkkel for kryptering av data og en annen separat, men relatert, nøkkel for dekryptering av data.

I denne veiledningen vil vi utnytte Sikkerhetsramme tilgjengelig på iOS for å kryptere og dekryptere data. Denne prosessen foregår under hetten, slik at vi ikke direkte vil samhandle med dette rammeverket. Vi bruker symmetrisk kryptering i vårt eksempelprogram.

De Sikkerhetsramme tilbyr en rekke andre tjenester, for eksempel Randomization-tjenester for å generere kryptografisk sikre tilfeldige tall, Sertifikat, Nøkkel og Trust Services for å administrere sertifikater, offentlige og private nøkler og tillitspolicyer. De Sikkerhetsramme er et lavt nivå rammeverk tilgjengelig på både iOS og OS X med C-baserte APIer.


Applikasjonsoversikt

I denne veiledningen vil jeg vise deg hvordan du kan bruke nøkkelringstjenesten API og symmetrisk kryptering i et iOS-program. Vi lager et lite program som sikkert lagrer bilder tatt av brukeren.

I dette prosjektet bruker vi Sam Soffes SSKeychain, en Objective-C wrapper for interaksjon med nøkkelringstjenesten API. For kryptering og dekryptering bruker vi RNCryptor, et tredjeparts krypteringsbibliotek.


Krypteringsdata med RNCryptor

RNCryptor-biblioteket er et godt valg for kryptering og dekryptering av data. Prosjektet brukes av mange utviklere og vedlikeholdes aktivt av sine skapere. Biblioteket tilbyr en enkel å bruke Objective-C API. Hvis du er kjent med kakao og objektiv-C, vil du finne det enkelt å bruke. Bibliotekets hovedtrekk er oppført nedenfor.

  • AES-256 kryptering
  • CBC-modus
  • Passord strekker seg med PBKDF2
  • Passord Salting
  • Tilfeldig IV
  • Krypter-deretter-Hash HMAC

Applikasjonsflyt

Før vi begynner å bygge applikasjonen, la meg vise deg hva den typiske strømmen av applikasjonen vil se ut.

  • Når brukeren starter programmet, presenteres hun med en visning for å logge på.
  • Hvis hun ikke har opprettet en konto ennå, legges hennes legitimasjon til nøkkelringen, og hun er logget på.
  • Hvis hun har en konto, men angir et feil passord, vises en feilmelding.
  • Når hun er logget inn, har hun tilgang til bildene hun er tatt med søknaden. Bildene lagres sikkert av søknaden.
  • Når hun tar et bilde med enhetens kamera eller plukker et bilde fra fotobiblioteket, blir bildet kryptert og lagret i programmets dokumenter katalog.
  • Når hun bytter til et annet program eller enheten blir låst, blir hun automatisk utmeldt.

Bygg applikasjonen

Trinn 1: Prosjektoppsett

Brann opp Xcode og opprett et nytt prosjekt ved å velge Enkeltvisningsprogram mal fra listen over maler.


Gi navnet navnet på prosjektet Sikre bilder og sett Enhetsfamilie til iPhone. Fortell Xcode hvor du vil lagre prosjektet og trykke Skape.


Trinn 2: Rammer

Det neste trinnet er å knytte prosjektet mot Sikkerhet og Mobile Core Services rammeverk. Velg prosjektet i Prosjektnavigator til venstre, velg det første målet som heter Sikre bilder, og åpne Bygg faser fanen øverst. Utvid Link binær med biblioteker skuff og len prosjektet mot Sikkerhet og Mobile Core Services rammer.


Trinn 3: Avhengigheter

Som nevnt tidligere bruker vi SSKeychain-biblioteket og RNCryptor-biblioteket. Last ned disse avhengighetene og legg dem til prosjektet. Pass på at du kopierer filene til prosjektet ditt og legger dem til Sikre bilder mål som vist på skjermbildet nedenfor.


Trinn 4: Opprette klasser

Vi vil vise brukerens bilder i en samlingsvisning, noe som betyr at vi må underklasse UICollectionViewController i tillegg til UICollectionViewCell. Å velge Ny> Fil ... fra Fil meny, opprett en underklasse av UICollectionViewController, og nev det MTPhotosViewController. Gjenta dette trinnet en gang til MTPhotoCollectionViewCell, som er en underklasse av UICollectionViewCell.

Trinn 5: Opprette brukergrensesnittet

Åpne prosjektets hoved storyboard og oppdater storyboardet som vist på skjermbildet nedenfor. Storyboardet inneholder to visningskontrollere, en forekomst av MTViewController, som inneholder to tekstfelter og en knapp, og en forekomst av MTPhotosViewController. De MTViewController forekomsten er innebygd i en navigasjonskontrollenhet.

Vi må også opprette en segue fra MTViewController eksempel på MTPhotosViewController forekomst. Sett segueidentifikatoren til photosViewController. De MTPhotosViewController forekomsten bør også inneholde et strekkknappelement som vist på skjermbildet under.


For å gjøre alt dette arbeidet, må vi oppdatere grensesnittet til MTViewController som vist under. Vi erklærer et uttak for hvert tekstfelt og en handling som utløses av knappen. Foreta de nødvendige tilkoblingene i prosjektets hovedfortegnelse.

 #importere  @interface MTViewController: UIViewController @property (svak, ikkeatomisk) IBOutlet UITextField * brukernavnTextField; @property (svak, ikkeatomisk) IBOutlet UITextField * passwordTextField; - (IBAction) login: (id) avsender; @slutt

I MTPhotosViewController klasse, erklære en eiendom som heter brukernavn for å lagre brukernavnet til den innloggede brukeren og angi en handling for bar-knappelementet. Ikke glem å koble til handlingen med barknappen i hovedfortegnelsen.

 #importere  @interface MTPhotosViewController: UICollectionViewController @property (copy, nonatomic) NSString * brukernavn; - (IBAction) bilder: (id) avsender; @slutt

Trinn 6: Implementering MTViewController

I MTViewController.m, legg til en importerklæring for MTPhotosViewController klasse, den SSKeychain klassen og MTAppDelegate klasse. Vi overholder også MTViewController klasse til UIAlertViewDelegate protokollen.

 #import "MTViewController.h" #import "SSKeychain.h" #import "MTAppDelegate.h" #import "MTPhotosViewController.h" @interface MTViewController ()  @slutt

Det neste trinnet er å implementere Logg Inn: handling vi erklærte tidligere. Vi kontrollerer først om brukeren allerede har opprettet en konto ved å hente passordet for kontoen. Hvis dette er sant, bruker vi programmets nøkkelring for å se om passordet som er oppgitt av brukeren, samsvarer med det som er lagret i nøkkelringen. Metodene som tilbys av SSKeychain biblioteket gjør det enkelt å lese og manipulere data lagret i programmets nøkkelring.

 - (IBAction) logg inn: (id) sender if (self.usernameTextField.text.length> 0 && self.passwordTextField.text.length> 0) NSString * passord = [SSKeychain passwordForService: @ "MyPhotos" -konto: self.usernameTextField .tekst]; hvis (password.length> 0) if ([self.passwordTextField.text isEqualToString: passord]) [selv utførerSegueWithIdentifier: @ "photosViewController" avsender: null];  ellers UIAlertView * alertView = [[UIAlertView alloc] initWithTitle: @ "Feil pålogging" melding: @ "Ugyldig brukernavn / passord kombinasjon." delegere: null avbrytButtonTitle: @ "OK" otherButtonTitles: null]; [alertView show];  ellers UIAlertView * alertView = [[UIAlertView allok] initWithTitle: @ "Ny konto" melding: @ "Vil du opprette en konto?" delegere: self cancellButtonTitle: @ "Cancel" otherButtonTitles: @ "OK", null); [alertView show];  ellers UIAlertView * alertView = [[UIAlertView allok] initWithTitle: @ "Feilinngang" melding: @ "Brukernavn og / eller passord kan ikke være tomt." delegere: null avbrytButtonTitle: @ "OK" otherButtonTitles: null]; [alertView show]; 

Vi har satt visningskontrolleren som varselvisningens delegat, noe som betyr at vi må implementere UIAlertViewDelegate protokoll. Ta en titt på implementeringen av alertView: clickedButtonAtIndex: Vist under.

 -(void) alertView: (UIAlertView *) alertView klikketButtonAtIndex: (NSInteger) buttonIndex switch (buttonIndex) tilfelle 0: break; tilfelle 1: [self createAccount]; gå i stykker; standard: break; 

I Opprett konto, vi utnytter SSKeychain klasse for å lagre brukernavn og passord sikkert valgt av brukeren. Vi ringer da performSegueWithIdentifier: avsender:.

 - (void) createAccount BOOL resultat = [SSKeychain setPassword: self.passwordTextField.text forService: @ "MyPhotos" -konto: self.usernameTextField.text]; hvis (resultat) [selv utførerSegueWithIdentifier: @ "photosViewController" avsender: null); 

I prepareForSegue: avsender:, vi får en referanse til MTPhotosViewController eksempel, sett sin brukernavn eiendom med verdien av usernameTextField, og tilbakestill passwordTextField.

 - (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) avsender MTPhotosViewController * photosViewController = segue.destinationViewController; photosViewController.username = self.usernameTextField.text; self.passwordTextField.text = nil; 

Trinn 7: Implementering MTPhotosCollectionViewCell

Åpen MTPhotosCollectionViewCell.h og erklære et utløp som heter bildeVis av type UIImageView.

 #importere  @interface MTPhotoCollectionViewCell: UICollectionViewCell @property (svak, ikkeatomisk) IBOutlet UIImageView * imageView; @slutt

Åpne hovedfortegnelsen og legg til en UIImageView forekomst til prototypecellen til MTPhotosViewController forekomst. Velg prototypecellen (ikke bildevisningen) og sett sin klasse til MTPhotosCollectionViewCell i Identitetsinspektør til høyre. Med prototypecellen fortsatt valgt, åpner du Attributtsinspektør og sett inn identifikatoren til Fotocelle.

Trinn 8: Implementering MTPhotosViewController

Begynn med å importere nødvendige overskriftsfiler i MTPhotosViewController.m som vist under. Vi må også deklarere to egenskaper, bilder for å lagre mengden bilder som samlingsvisningen vil vise og filepath for å holde en referanse til filbanen. Du har kanskje lagt merke til at MTPhotosViewController klassen stemmer overens med UIActionSheetDelegate, UINavigationControllerDelegate, og UIImagePickerControllerDelegate protokoller.

 #import "MTPhotosViewController.h" #import  #import "RNDecryptor.h" #import "RNEncryptor.h" #import "MTPhotoCollectionViewCell.h" @interface MTPhotosViewController ()  @property (strong, nonatomic) NSMutableArray * bilder; @property (copy, nonatomic) NSString * filePath; @slutt

Jeg har også implementert en praktisk eller hjelpemetode, setupUserDirectory, for å lage og sette opp de nødvendige katalogene der vi lagrer brukerens data. I prepareData, programmet dekrypterer bildene som er lagret i brukerens sikre katalog. Se på implementeringene nedenfor.

 - (void) setupUserDirectory NSArray * stier = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); NSString * documents = [stier objectAtIndex: 0]; self.filePath = [documents stringByAppendingPathComponent: self.username]; NSFileManager * fileManager = [NSFileManager defaultManager]; hvis ([fileManager fileExistsAtPath: self.filePath]) NSLog (@ "Directory allerede til stede.");  else NSError * error = nil; [fileManager createDirectoryAtPath: self.filePath withIntermediateDirectories: JA attributter: null feil: & error]; hvis (feil) NSLog (@ "Kan ikke opprette katalog for bruker."); 
 - (void) prepareData self.photos = [[NSMutableArray alloc] init]; NSFileManager * fileManager = [NSFileManager defaultManager]; NSError * error = nil; NSArray * innhold = [fileManager contentOfDirectoryAtPath: self.filePath feil: & error]; hvis ([innholdstelling] &&! feil) NSLog (@ "Innhold i brukerens katalog.% @", innhold); for (NSString * filnavn i innhold) if ([fileName rangeOfString: @ ". securedData"]. lengde> 0) NSData * data = [NSData dataWithContentsOfFile: [self.filePath stringByAppendingPathComponent: fileName]]; NSData * decryptedData = [RNDecryptor decryptData: data withSettings: kRNCryptorAES256Settings passord: @ "A_SECRET_PASSWORD" feil: null]; UIImage * image = [UIImage imageWithData: decryptedData]; [self.photos addObject: image];  else NSLog (@ "Denne filen er ikke sikret.");  annet hvis (! [innholdstelling]) hvis (feil) NSLog (@ "Kan ikke lese innholdet i brukerens katalog.");  else NSLog (@ "Brukerens katalog er tom."); 

Invoke begge metodene i visningsregulatorens viewDidLoad metode som vist nedenfor.

 - (void) viewDidLoad [super viewDidLoad]; [selvoppsettUserDirectory]; [selvforberedende data]; 

Stangknappen i visningskontrollens navigasjonslinje viser et handlingsbilde som lar brukeren velge mellom enhetens kamera og fotobiblioteket.

 - (IBAction) bilder: (id) avsender UIActionSheet * actionSheet = [[UIActionSheet alloc] initWithTitle: @ "Velg kilde" delegat: self cancelButtonTitle: @ "Cancel" destructiveButtonTitle: ingen andreButtonTitles: @ "Camera", @ "Photo Library" , null]; [actionSheet showFromBarButtonItem: avsender animert: YES]; 

La oss implementere actionSheet: clickedButtonAtIndex: av UIActionSheetDelegate protokollen.

 - (void) actionSheet: (UIActionSheet *) actionSheet klikketButtonAtIndex: (NSInteger) buttonIndex if (buttonIndex < 2)  UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; imagePickerController.mediaTypes = @[(__bridge NSString *)kUTTypeImage]; imagePickerController.allowsEditing = YES; imagePickerController.delegate = self; if (buttonIndex == 0)  #if TARGET_IPHONE_SIMULATOR #else imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; #endif  else if ( buttonIndex == 1)  imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;  [self.navigationController presentViewController:imagePickerController animated:YES completion:nil];  

For å håndtere brukerens valg i bildevalgkontrollen, må vi implementere imagePickerController: didFinishPickingMediaWithInfo: av UIImagePickerControllerDelegate protokoll som vist nedenfor. Bildet er kryptert med encryptData av RNEncryptor bibliotek. Bildet er også lagt til i bilder array og samlingsvisningen er lastet opp.

 - (void) imagePickerController: (UIImagePickerController *) plukkeren didFinishPickingMediaWithInfo: (NSDictionary *) info UIImage * image = [info objectForKey: UIImagePickerControllerEditedImage]; hvis (! bilde) [info objectForKey: UIImagePickerControllerOriginalImage];  NSData * imageData = UIImagePNGRepresentation (bilde); NSString * imageName = [NSString stringWithFormat: @ "image-% d.securedData", self.photos.count + 1]; NSData * encryptedImage = [RNEncryptor encryptData: imageData withSettings: kRNCryptorAES256Settingspassord: @ "A_SECRET_PASSWORD" feil: null]; [encryptedImage writeToFile: [self.filePath stringByAppendingPathComponent: imageName] atomically: YES]; [self.photos addObject: image]; [self.collectionView reloadData]; [plukkeren dismissViewControllerAnimated: JA ferdigstillelse: null]; 

Før du kan bygge og kjøre programmet, må vi implementere UICollectionViewDataSource protokoll som vist nedenfor.

 - (NSInteger) collectionView: (UICollectionView *) collectionView numberOfItemsInSection: (NSInteger) seksjon return self.photos? self.photos.count: 0; 
 - (UICollectionViewCell *) collectionView: (UICollectionView *) collectionView cellForItemAtIndexPath: (NSIndexPath *) indexPath MTPhotoCollectionViewCell * celle = [collectionView dequeueReusableCellWithReuseIdentifier: @ "PhotoCell" forIndexPath: indexPath]; cell.imageView.image = [self.photos objectAtIndex: indexPath.row]; returcelle; 

Trinn 9: Håndtering av applikasjonsland

Hvis applikasjonen går til bakgrunnen, må brukeren bli logget ut. Dette er viktig fra et sikkerhetsperspektiv. For å oppnå dette må applikasjonsdelegatet ha en referanse til navigasjonskontrollen, slik at den kan komme til roten til kontrolleren av navigasjonsbunken. Begynn med å erklære en eiendom som heter navigationController i MTAppDelegate.h.

 #importere  @interface MTAppDelegate: UIResponder  @property (strong, nonatomic) UIWindow * vindu; @property (strong, nonatomic) UINavigationController * navigationController; @slutt

I visningsregulatorens viewDidLoad Metode, vi setter søknad delegatets navigationController eiendom som vist nedenfor. Husk at dette bare er en måte å håndtere dette på.

Jeg har satt ovennevnte eiendom i ViewController s viewDidLoad metode som vist nedenfor.

 - (void) viewDidLoad [super viewDidLoad]; MTAppDelegate * applicationDeleagte = (MTAppDelegate *) [[UIApplication sharedApplication] delegate]; [applicationDeleagte setNavigationController: self.navigationController]; 

I programdelegasjonen må vi oppdatere applicationWillResignActive: som vist under. Det er så enkelt. Resultatet er at brukeren er logget ut når applikasjonen mister fokus. Det vil beskytte brukerens bilder lagret i applikasjonen fra nysgjerrige øyne. Ulempen er at brukeren må logge på når applikasjonen blir aktiv igjen.

 - (ugyldig) applicationWillResignActive: (UIApplication *) søknad [self.navigationController popToRootViewControllerAnimated: NO]; 

Trinn 10: Bygg og kjør

Bygg prosjektet og kjør programmet for å sette det gjennom sine skritt.


Konklusjon

I denne opplæringen lærte du hvordan du bruker nøkkelringstjeneste-API-en til å lagre sensitive data, og du lærte også å kryptere bildedata på iOS. Legg igjen en kommentar i kommentarene nedenfor hvis du har spørsmål eller tilbakemelding.