Oavsett om du skapar en mobilapplikation eller en webbtjänst, är det viktigt att hålla känslig data säker och säkerhet har blivit en viktig aspekt av varje mjukvaruprodukt. I den här handledningen kommer jag att visa dig hur du säkert lagrar användaruppgifter med hjälp av programmets nyckelring och vi tar en titt på kryptering och dekryptering av användardata med hjälp av ett tredje parts bibliotek.
I denna handledning lär jag dig hur man skyddar känslig data på iOS-plattformen. Känslig data kan vara användarens kontouppgifter eller kreditkortsuppgifter. Typ av data är inte så viktigt. I den här handledningen använder vi IOS nyckelring och symmetrisk kryptering för att säkert lagra användarens data. Innan vi kommer in i nitty-gritty detaljer, skulle jag vilja ge dig en översikt över vad vi ska göra i denna handledning.
Även om denna handledning fokuserar på iOS, kan koncepten och teknikerna också användas på OS X.På IOS och OS X är en nyckelring en krypterad behållare för lagring av lösenord och annan data som behöver säkras. På OS X är det möjligt att begränsa nyckelring till vissa användare eller applikationer. På IOS har varje applikation dock en egen nyckelring som endast har programmet åtkomst till. Detta säkerställer att data som är lagrade i nyckelring är säker och otillgänglig av tredje part.
Tänk på att nyckelringen endast ska användas för att lagra små bitar av data, till exempel lösenord. Med den här artikeln hoppas jag kunna övertyga dig om värdet av att använda nyckelring på IOS och OS X istället för till exempel programmets standarddatabas, som lagrar data i vanlig text utan någon form av säkerhet.
På IOS kan en applikation använda nyckelringen via Keychain Services API. API: n ger ett antal funktioner för att manipulera data som lagras i programmets nyckelring. Ta en titt på funktionerna som finns tillgängliga på iOS.
SecItemAdd
Den här funktionen används för att lägga till ett objekt i programmets nyckelring.SecItemCopyMatching
Du använder den här funktionen för att hitta ett nyckelring objekt som ägs av programmet.SecItemDelete
Som namnet antyder kan den här funktionen användas för att ta bort ett objekt från programmets nyckelring.SecItemUpdate
Använd den här funktionen om du behöver uppdatera ett objekt i programmets nyckelring.De Keychain Services API är ett C API, men jag hoppas det hindrar dig inte från att använda den. Var och en av ovanstående funktioner accepterar en ordlista (CFDictionaryRef
), som innehåller en tangentvärdespar för objektklassen och valfria parametrar för attributvärden. Den exakta meningen och syftet med varje kommer att bli tydlig när vi börjar använda API: n i ett exempel.
När du diskuterar kryptering hör du vanligtvis om två typer av kryptering, symmetrisk och asymmetrisk kryptering. Symmetrisk kryptering använder å ena sidan en gemensam nyckel för kryptering och dekryptering av data. Asymmetrisk kryptering använder å andra sidan en nyckel för kryptering av data och en annan separat men relaterad nyckel för att dekryptera data.
I den här handledningen använder vi oss av Säkerhetsramar tillgänglig på iOS för att kryptera och dekryptera data. Denna process sker under huven så vi kommer inte direkt att interagera med denna ram. Vi använder symmetrisk kryptering i vårt exempelprogram.
De Säkerhetsramar erbjuder ett antal andra tjänster, till exempel Randomization-tjänster för att generera kryptografiskt säkra slumptal, certifikat, nyckel och förtroende för hantering av certifikat, offentliga och privata nycklar och förtroendepolicyer. De Säkerhetsramar är en ram på låg nivå tillgänglig på både iOS och OS X med C-baserade API.
I denna handledning kommer jag att visa dig hur du kan använda Keychain Services API och symmetrisk kryptering i en iOS-applikation. Vi skapar en liten applikation som säkert lagrar foton som tas av användaren.
I det här projektet använder vi Sam Soffes SSKeychain, ett Objective-C wrapper för att interagera med Keychain Services API. För kryptering och dekryptering använder vi RNCryptor, ett krypteringsbibliotek från tredje part.
RNCryptor-biblioteket är ett bra val för kryptering och dekryptering av data. Projektet används av många utvecklare och underhålls aktivt av sina skapare. Biblioteket erbjuder ett enkelt att använda Objective-C API. Om du är bekant med kakao och objektiv-C, hittar du det lätt att använda. Bibliotekets huvudfunktioner listas nedan.
Innan vi börjar bygga applikationen, låt mig visa dig vad det typiska flödet av ansökan kommer att se ut.
Avbryt Xcode och skapa ett nytt projekt genom att välja Enkel visningsprogram mall från listan med mallar.
Namn på projektet Säkra foton och ställa in Enhetsfamilj till iPhone. Berätta Xcode där du vill spara projektet och träffa Skapa.
Nästa steg är att länka projektet mot säkerhet och Mobile Core Services ramar. Välj projektet i Project Navigator till vänster, välj det första målet som heter Säkra foton, och öppna Bygga faser fliken längst upp. Expandera Länk binär med bibliotek lådan och länka projektet mot säkerhet och Mobile Core Services ramar.
Som jag nämnde tidigare använder vi SSKeychain-biblioteket och RNCryptor-biblioteket. Ladda ner dessa beroenden och lägg till dem i projektet. Se till att kopiera filerna till ditt projekt och lägg till dem i Säkra foton målet som visas på skärmdumpen nedan.
Vi visar användarens foton i en samlingsvy, vilket innebär att vi behöver subklass UICollectionViewController
såväl som UICollectionViewCell
. Välj Ny> Fil ... från Fil meny, skapa en underklass av UICollectionViewController
, och namnge det MTPhotosViewController
. Upprepa detta steg en gång till för MTPhotoCollectionViewCell
, vilket är en underklass av UICollectionViewCell
.
Öppna projektets huvud storyboard och uppdatera storyboardet som visas på skärmdumpen nedan. Berättelsen innehåller två visningsstyrare, en förekomst av MTViewController
, som innehåller två textfält och en knapp och en förekomst av MTPhotosViewController
. De MTViewController
Exempel är inbäddad i en navigeringsenhet.
Vi måste också skapa en segue från MTViewController
instans till MTPhotosViewController
exempel. Ange segusens identifierare till photosViewController
. De MTPhotosViewController
Instans bör också innehålla en streckknappsartikel som visas på skärmdumpen nedan.
För att göra allt detta måste vi uppdatera gränssnittet för MTViewController
enligt nedanstående. Vi förklarar ett uttag för varje textfält och en åtgärd som utlöses av knappen. Gör de nödvändiga anslutningarna i projektets huvudsakliga storyboard.
#importera@interface MTViewController: UIViewController @property (svag, ickeatomisk) IBOutlet UITextField * användarnamnTextField; @property (svag, ickeatomisk) IBOutlet UITextField * passwordTextField; - (IBAction) inloggning: (id) avsändare; @slutet
I MTPhotosViewController
klass, förklara en egendom som heter Användarnamn
för att lagra användarnamnet för den för närvarande inloggade användaren och förklara en åtgärd för knappknappsposten. Glöm inte att ansluta åtgärden med knappknappsposten i huvud storyboard.
#importera@interface MTPhotosViewController: UICollectionViewController @property (copy, nonatomic) NSString * användarnamn; - (IBAction) foton: (id) avsändare; @slutet
MTViewController
I MTViewController.m
, lägg till ett import uttalande för MTPhotosViewController
klass, the SSKeychain
klass, och MTAppDelegate
klass. Vi överensstämmer också med MTViewController
klass till UIAlertViewDelegate
protokoll.
#import "MTViewController.h" #import "SSKeychain.h" #import "MTAppDelegate.h" #import "MTPhotosViewController.h" @interface MTViewController ()@slutet
Nästa steg är att genomföra logga in:
åtgärder vi förklarade tidigare. Vi kontrollerar först om användaren redan har skapat ett konto genom att hämta lösenordet för kontot. Om det är sant använder vi programmets nyckelring för att se om lösenordet som användaren har angett matchar den som lagrats i nyckelringen. De metoder som tillhandahålls av SSKeychain biblioteket gör det enkelt att läsa och manipulera data lagrade i programmets nyckelring.
- (IBAction) login: (id) avsändare if (self.usernameTextField.text.length> 0 && self.passwordTextField.text.length> 0) NSString * lösenord = [SSKeychain passwordForService: @ "MyPhotos" konto: self.usernameTextField .text]; om (password.length> 0) if ([self.passwordTextField.text isEqualToString: lösenord]) [self performSegueWithIdentifier: @ "photosViewController" avsändare: nil]; annan UIAlertView * alertView = [[UIAlertView-tilldelningen] initWithTitle: @ "Fel inloggning" meddelande: @ "Ogiltigt användarnamn / lösenordskombination." delegera: noll cancelButtonTitle: @ "OK" otherButtonTitles: nil]; [alertView show]; else UIAlertView * alertView = [[UIAlertView-tilldelningen] initWithTitle: @ "New Account" -meddelandet: @ "Vill du skapa ett konto?" delegera: self cancelButtonTitle: @ "Cancel" otherButtonTitles: @ "OK", noll]; [alertView show]; annat UIAlertView * alertView = [[UIAlertView-tilldelningen] initWithTitle: @ "Felinmatning" meddelande: @ "Användarnamn och / eller lösenord kan inte vara tomt." delegera: noll cancelButtonTitle: @ "OK" otherButtonTitles: nil]; [alertView show];
Vi har ställt vyskontrollen som varningsvyns delegat, vilket innebär att vi måste implementera UIAlertViewDelegate
protokoll. Ta en titt på genomförandet av alertView: clickedButtonAtIndex:
visas nedan.
-(void) alertView: (UIAlertView *) alertVisa clickedButtonAtIndex: (NSInteger) buttonIndex switch (buttonIndex) fall 0: break; fall 1: [self createAccount]; ha sönder; standard: break;
I skapa konto
, vi utnyttjar SSKeychain
klass för att säkert lagra användarnamnet och lösenordet som användaren valt. Vi ringer sedan performSegueWithIdentifier: avsändare:
.
- (void) createAccount BOOL result = [SSKeychain setPassword: self.passwordTextField.text forService: @ "MyPhotos" -konto: self.usernameTextField.text]; om (resultat) [själv utförSegueWithIdentifier: @ "photosViewController" avsändare: noll];
I prepareForSegue: avsändare:
, vi får en hänvisning till MTPhotosViewController
Exempel, sätt dess Användarnamn
egendom med värdet av usernameTextField
, och återställ passwordTextField
.
- (void) prepareForSegue: (UIStoryboardSegue *) segue avsändare: (id) avsändare MTPhotosViewController * photosViewController = segue.destinationViewController; photosViewController.username = self.usernameTextField.text; self.passwordTextField.text = nil;
MTPhotosCollectionViewCell
Öppna MTPhotosCollectionViewCell.h och deklarera ett utlopp som heter Imageview
av typ UIImageView
.
#importera@interface MTPhotoCollectionViewCell: UICollectionViewCell @property (svag, ickeatomisk) IBOutlet UIImageView * imageView; @slutet
Öppna huvud storyboardet och lägg till en UIImageView
Exempel på prototypcellen i MTPhotosViewController
exempel. Välj prototypcellen (inte bildvyn) och sätt dess klass till MTPhotosCollectionViewCell
i Identitetsinspektör till höger. Med prototypcellen fortfarande vald, öppna Attribut Inspector och ange identifieraren till FOTOCELL
.
MTPhotosViewController
Börja med att importera nödvändiga rubrikfiler i MTPhotosViewController.m enligt nedanstående. Vi måste också deklarera två egenskaper, foton
för att lagra en uppsättning bilder som samlingsvisningen kommer att visa och sökväg
för att behålla en referens till filbanan. Du kanske har märkt att MTPhotosViewController
klassen överensstämmer med UIActionSheetDelegate
, UINavigationControllerDelegate
, och UIImagePickerControllerDelegate
protokoll.
#import "MTPhotosViewController.h" #import#import "RNDecryptor.h" #import "RNEncryptor.h" #import "MTPhotoCollectionViewCell.h" @interface MTPhotosViewController () @property (stark, icke-atomisk) NSMutableArray * foton; @property (copy, nonatomic) NSString * filePath; @slutet
Jag har också implementerat en bekvämlighets- eller hjälparätt, setupUserDirectory
, för att skapa och konfigurera nödvändiga kataloger där vi lagrar användarens data. I prepareData
, programmet dekrypterar bilderna som lagras i användarens säkra katalog. Ta en titt på deras implementeringar nedan.
- (void) setupUserDirectory NSArray * paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); NSString * documents = [paths objectAtIndex: 0]; self.filePath = [documents stringByAppendingPathComponent: self.username]; NSFileManager * fileManager = [NSFileManager defaultManager]; om ([fileManager fileExistsAtPath: self.filePath]) NSLog (@ "Directory redan närvarande."); else NSError * error = nil; [fileManager createDirectoryAtPath: self.filePath withIntermediateDirectories: JA attribut: nil error: & error]; om (fel) NSLog (@ "Kan inte skapa katalog för användare.");
- (void) prepareData self.photos = [[NSMutableArray alloc] init]; NSFileManager * fileManager = [NSFileManager defaultManager]; NSError * error = nil; NSArray * innehåll = [fileManager contentOfDirectoryAtPath: self.filePath error: & error]; om ([content count] &&! error) NSLog (@ "Innehållet i användarens katalog.% @", innehåll); för (NSString * filnamn i innehåll) if ([fileName rangeOfString: @ ".DecuredData"]. längd> 0) NSData * data = [NSData dataWithContentsOfFile: [self.filePath stringByAppendingPathComponent: fileName]]; NSData * decryptedData = [RNDecryptor decryptData: data withSettings: kRNCryptorAES256Sättnings lösenord: @ "A_SECRET_PASSWORD" fel: noll]; UIImage * image = [UIImage imageWithData: decryptedData]; [self.photos addObject: bild]; else NSLog (@ "Den här filen är inte säker."); annars om (! [innehållsräkning]) om (fel) NSLog (@ "Kan inte läsa innehållet i användarens katalog."); else NSLog (@ "Användarens katalog är tom.");
Invoke båda metoderna i visningskontrollerns viewDidLoad
metod som visas nedan.
- (void) viewDidLoad [super viewDidLoad]; [self setupUserDirectory]; [self preparationData];
Stångknappsposten i visningsregulatorens navigeringsfält visar ett handlingsblad som gör det möjligt för användaren att välja mellan enhetens kamera och fotobiblioteket.
- (IBAction) foton: (id) avsändare UIActionSheet * actionSheet = [[UIActionSheet alloc] initWithTitle: @ "Välj källa" delegat: self cancelButtonTitle: @ "Avbryt" destructiveButtonTitle: nil otherButtonTitles: @ "Camera", @ "Photo Library" , noll]; [actionSheet showFromBarButtonItem: avsändare animerad: YES];
Låt oss genomföra actionSheet: clickedButtonAtIndex:
av UIActionSheetDelegate
protokoll.
- (void) actionSheet: (UIActionSheet *) actionSheet clickedButtonAtIndex: (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];
För att hantera användarens val i bildväljaren måste vi implementera imagePickerController: didFinishPickingMediaWithInfo:
av UIImagePickerControllerDelegate
protokoll som visas nedan. Bilden är krypterad med encryptData
av RNEncryptor
bibliotek. Bilden läggs också till i foton
array och samlingsvyn uppdateras.
- (void) imagePickerController: (UIImagePickerController *) plockare didFinishPickingMediaWithInfo: (NSDictionary *) info UIImage * image = [info objectForKey: UIImagePickerControllerEditedImage]; om (! bild) [info objectForKey: UIImagePickerControllerOriginalImage]; NSData * imageData = UIImagePNGRepresentation (bild); NSString * imageName = [NSString stringWithFormat: @ "image-% d.securedData", self.photos.count + 1]; NSData * encryptedImage = [RNEncryptor encryptData: imageData withSettings: kRNCryptorAES256Sättnings lösenord: @ "A_SECRET_PASSWORD" fel: noll]; [encryptedImage writeToFile: [self.filePath stringByAppendingPathComponent: imageName] atomically: YES]; [self.photos addObject: bild]; [self.collectionView reloadData]; [picker dismissViewControllerAnimated: JA slutförd: noll];
Innan du kan bygga och köra programmet måste vi implementera UICollectionViewDataSource
protokoll som visas nedan.
- (NSInteger) collectionView: (UICollectionView *) collectionView numberOfItemsInSection: (NSInteger) avsnitt return self.photos? self.photos.count: 0;
- (UICollectionViewCell *) collectionView: (UICollectionView *) collectionVisa cellForItemAtIndexPath: (NSIndexPath *) indexPath MTPhotoCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier: @ "PhotoCell" förIndexPath: indexPath]; cell.imageView.image = [self.photos objectAtIndex: indexPath.row]; returcell;
Om applikationen går till bakgrunden måste användaren vara utloggad. Detta är viktigt ur ett säkerhetsperspektiv. För att åstadkomma detta måste applikationsdelegatet ha en hänvisning till navigeringskontrollen så att den kan dyka upp i rotationsbildsregulatorn i navigeringsstapeln. Börja med att deklarera en egendom som heter navigationController
i MTAppDelegate.h.
#importera@interface MTAppDelegate: UIResponder @property (strong, nonatomic) UIWindow * fönster; @property (stark, icke-atomisk) UINavigationController * navigationController; @slutet
I visningsregulatorens viewDidLoad
metod, vi ställer in ansökningsdelegatets navigationController
egendom som visas nedan. Tänk på att detta bara är ett sätt att hantera detta.
Jag har satt ovanstående egendom i ViewController s
viewDidLoad
metod som visas nedan.
- (void) viewDidLoad [super viewDidLoad]; MTAppDelegate * applicationDeleagte = (MTAppDelegate *) [[UIApplication sharedApplication] delegate]; [applicationDeleagte setNavigationController: self.navigationController];
I ansökningsdelegatet behöver vi uppdatera applicationWillResignActive:
enligt nedanstående. Så enkelt är det. Resultatet är att användaren är utloggad när applikationen förlorar fokus. Det kommer att skydda användarens bilder lagrade i applikationen från nyfikna ögon. Nackdelen är att användaren måste logga in när applikationen blir aktiv igen.
- (void) applicationWillResignActive: (UIApplication *) applikation [self.navigationController popToRootViewControllerAnimated: NO];
Bygg projektet och kör programmet för att sätta det genom sina steg.
I denna handledning lärde du dig hur du använder verktyget Keychain Services för att lagra känslig data och du lärde dig också hur man krypterar bilddata på iOS. Lämna en kommentar i kommentarerna nedan om du har några frågor eller feedback.