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.
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.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.
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.
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.
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.
Før vi begynner å bygge applikasjonen, la meg vise deg hva den typiske strømmen av applikasjonen vil se ut.
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.
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.
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.
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
.
Å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
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;
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
.
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;
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];
Bygg prosjektet og kjør programmet for å sette det gjennom sine skritt.
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.