Generic selectors
Exact matches only
Search in title
Search in content

Wie können Sie die neue Touch ID Fingerprint API in Ihrer iPhone App verwenden?

22.07.2014 / 0 Comments

Vor kurzem haben wir die neue Touch ID Fingerprint-Prüfung als biometrisches Anmeldeverfahren in eine Beta-Version unserer SecSign App integriert. Die SecSign ID bietet Nutzern ein sicheres Anmeldeverfahren für Webseiten und Programme, das die Notwendigkeit von Passwörtern beseitigt.

Diese alternative Anmeldeoption verhindert den Diebstahl von Passwörtern und stellt sicher, dass Nutzerkonten weder durch Hacker- oder Phishing-Angriffe noch durch Schadprogramme gefährdet werden können.

Um anderen Entwicklern eine Hilfestellung zu bieten, möchten wir unsere Erfahrungen, die wir mit der Integration von der Touch ID Api in Objective-C iPhone-Anwendungen gemacht haben, mit Ihnen teilen.

Anforderungen für die Integration des Touch ID Fingerprints:

• XCode 6

•  iPhone 5s mit iOS 8

 

Diese Anleitung verdeutlich, wie man die folgenden drei Ziele erreicht:

1. Stellen Sie fest, ob das iPhone einen Fingerabdruck prüfen kann bzw. die Touch ID Api unterstützt, und ob der Nutzer bereits einen Fingerabdruck hinterlegt hat

2. Überprüfen Sie einen Fingerabdruck

3. Überprüfen Sie einen Fingerabdruck oder die PIN für das Gerät (je nachdem, welche Authentifizierungsart der Nutzer auswählt)
Wie auf der Abbildung zu sehen, kann der Nutzer wählen, ob er für die Authentifizierung seinen Fingerabdruck oder Passcode/PIN verwendet.
zwei-faktor_Authentifizierung_mit_touchID

1. Überprüfen Sie, ob das Gerät des Nutzers die Überprüfung per Fingerabdruck unterstützt und ob für das iPhone bereits ein Fingerabdruck registriert wurde

Zuerst muss LocalAuthentication importiert werden. Das erfordert XCode 6:

// Determine a string which the device will display in the fingerprint view explaining the reason for the fingerprint scan.
NSString * secUseOperationPrompt = @"Authenticate for server login";
// The keychain operation shall be performed by the global queue. Otherwise it might just nothing happen.
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
  // Create the keychain query attributes using the values from the first part of the code.
  NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                          (__bridge id)(kSecClassGenericPassword), kSecClass,
                          keychainItemIdentifier, kSecAttrAccount,
                          keychainItemServiceName, kSecAttrService,
                          secUseOperationPrompt, kSecUseOperationPrompt,
                          nil];
   // Start the query and the fingerprint scan and/or device passcode validation
   CFTypeRef result = nil;
   OSStatus userPresenceStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
    // Ignore the found content of the key chain entry (the dummy password) and only evaluate the return code.
   if (noErr == userPresenceStatus)
   {
       NSLog(@"Fingerprint or device passcode validated.");
   }
  else
  {
      NSLog(@"Fingerprint or device passcode could not be validated. Status %d.", (int) userPresenceStatus);
  }
  // To process the result at this point there would be a call to delegate method which
  // would do its work like GUI operations in the main queue. That means it would start
  // with something like:
  //   dispatch_async(dispatch_get_main_queue(), ^{
});

2. Wie der Touch ID Fingerabdruck validiert und verifiziert werden kann

import LocalAuthentication;
// Get the local authentication context:
LAContext *context = [[LAContext alloc] init];

Starten Sie die Überprüfung. Dieser Aufruf kehrt sofort zurück und wartet nicht auf das Erbgebnis. Somit muss eine Funktion bereitgestellt werden, die einmal aufgerufen wird, sobald die Prüfung des Fingerabdrucks abgeschlossen ist. Zusätzlich kann ein String zur Verfügung gestellt werden, den das Gerät in der Fingerprint-Ansicht anzeigt und der den Grund für die Prüfung des Fingerabdrucks beschreibt.

[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"Authenticate for server login" reply:^(BOOL success, NSError *authenticationError){
    if (success) {
        NSLog(@"Fingerprint validated.");
    }
    else {
        NSLog(@"Fingerprint validation failed: %@.", authenticationError.localizedDescription);
    }
}];

Achtung: Wenn die Fingerprint-Ansicht von iOS erscheint, führt dies dazu, dass applicationWillResignActive der Anwendung aufgerufen wird. Wenn Sie so wie wir einen Clean-up-Code zur Verfügung haben, möchten Sie ihn vielleicht zum applicationDidEnterBackground bewegen. applicationDidEnterBackground wird aufgerufen, wenn die Anwendung sich nun tatsächlich im Hintergrund befindet. Das Aufrufen von applicationDidEnterBackground erfolgt also nicht für den Scan des Fingerabdrucks, sondern nur beim Schließen der Anwendung/bei der Verwendung der Home-Taste.

 

3. Überprüfung eines Fingerabdrucks oder Passcodes des Nutzergeräts (Wahloptionen für den Nutzer)

Was geschieht, wenn die Überprüfung des Fingerabdrucks fehlschlägt? Der Nutzer erwartet die Eingabe eines Passcodes ähnlich der Eingabe eines Passcodes, um das iPhone zu entsperren. Wenn man jedoch LocalAuthentication wie oben beschrieben benutzt, wird das Gerät einen Fehler anzeigen, wenn die Prüfung des Fingerabdrucks fehlschlägt. Danach gibt es keine Möglichkeit mehr, die Eingabe des Passcodes für das Gerät zu starten. Daher ist ein anderer Ansatz erforderlich.

Beginnend mit iOS 8 können Schlüsselbund-/Keychain-Einträge neue Zugangsbedingungen aufweisen, die es erfordern, die Anwesenheit des Nutzers zu überprüfen, um den Schlüsselbund-/Keychain-Eintrag zu lesen. Diese Überprüfung besteht nun aus der Prüfung des Fingerabdrucks mit der Eingabe des Gerätepasscodes beim Fehlschlagen der Fingerabdruckprüfung. Alles, was wir also machen müssen, ist einen Dummywert im Schlüsselbund zu speichern und zu lesen, wann immer wir einen Fingerabdruck-Scan und/oder Gerätepasscode auf seine Gültigkeit überprüfen möchten. Hier sehen Sie nun den entsprechenden Code. Den ersten Teil bildet der Schlüsselbund-/Keychain-Eintrag mit der Überprüfung der Zugangsbedingungen, die die Anwesenheit des Nutzers voraussetzen.

Dieser Code muss nur einmal ausgeführt werden.

@import LocalAuthentication;
// The identifier and service name together will uniquely identify the keychain entry.
NSString * keychainItemIdentifier = @"fingerprintKeychainEntry";
NSString * keychainItemServiceName = @"com.secsign.secsign";
// The content of the password is not important.
NSData * pwData = [@"the password itself does not matter" dataUsingEncoding:NSUTF8StringEncoding];
// Create the keychain entry attributes.
NSMutableDictionary	* attributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                                      (__bridge id)(kSecClassGenericPassword), kSecClass,
                                      keychainItemIdentifier, kSecAttrAccount,
                                      keychainItemServiceName, kSecAttrService, nil];
// Require a fingerprint scan or passcode validation when the keychain entry is read.
// Apple also offers an option to destroy the keychain entry if the user ever removes the
// passcode from his iPhone, but we don't need that option here.
CFErrorRef accessControlError = NULL;
SecAccessControlRef accessControlRef = SecAccessControlCreateWithFlags(
                                                                         kCFAllocatorDefault,
                                                                         kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
                                                                         kSecAccessControlUserPresence,
                                                                         &accessControlError);
if (accessControlRef == NULL || accessControlError != NULL)
{
    NSLog(@"Cannot create SecAccessControlRef to store a password with identifier “%@” in the key chain: %@.", keychainItemIdentifier, accessControlError);
    return nil;
}
attributes[(__bridge id)kSecAttrAccessControl] = (__bridge id)accessControlRef;
// In case this code is executed again and the keychain item already exists we want an error code instead of a fingerprint scan.
attributes[(__bridge id)kSecUseNoAuthenticationUI] = @YES;
attributes[(__bridge id)kSecValueData] = pwData;
CFTypeRef result;
OSStatus osStatus = SecItemAdd((__bridge CFDictionaryRef)attributes, &result);
if (osStatus != noErr)
{
    NSError * error = [[NSError alloc] initWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
    NSLog(@"Adding generic password with identifier “%@” to keychain failed with OSError %d: %@.", keychainItemIdentifier, (int)osStatus, error);
}

Der zweite Teil des Codes sollte aufgerufen werden, wann immer die Überprüfung eines Gerätepasscodes oder des Scans eines Fingerabdrucks erforderlich ist.

// Determine a string which the device will display in the fingerprint view explaining the reason for the fingerprint scan.
NSString * secUseOperationPrompt = @"Authenticate for server login";
// The keychain operation shall be performed by the global queue. Otherwise it might just nothing happen.
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
  // Create the keychain query attributes using the values from the first part of the code.
  NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                          (__bridge id)(kSecClassGenericPassword), kSecClass,
                          keychainItemIdentifier, kSecAttrAccount,
                          keychainItemServiceName, kSecAttrService,
                          secUseOperationPrompt, kSecUseOperationPrompt,
                          nil];
   // Start the query and the fingerprint scan and/or device passcode validation
   CFTypeRef result = nil;
   OSStatus userPresenceStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
    // Ignore the found content of the key chain entry (the dummy password) and only evaluate the return code.
   if (noErr == userPresenceStatus)
   {
       NSLog(@"Fingerprint or device passcode validated.");
   }
  else
  {
      NSLog(@"Fingerprint or device passcode could not be validated. Status %d.", (int) userPresenceStatus);
  }
  // To process the result at this point there would be a call to delegate method which
  // would do its work like GUI operations in the main queue. That means it would start
  // with something like:
  //   dispatch_async(dispatch_get_main_queue(), ^{
});

Und dies für den Fall, dass Sie noch eine Angabe hinzufügen möchten, die verhindert, dass der iOS 8 Spezialcode auf einer älteren iOS-Version aufgerufen wird:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1)
{
    // convince the user of an iOS update
}

Das war´s!

Über ein Feedback von Ihnen würden wir uns sehr freuen. Um den Code einmal in Aktion zu sehen, schauen Sie sich gerne unser YouTube Demo-Video an, das die weltweit erste Webanmeldung mit der Apple Touch ID zeigt. Natürlich sind Sie auch jederzeit herzlich willkommen, unsere Webseite zu besuchen, um mehr über unsere aktuellen SecSign ID Lösungen zu erfahren und die neueste Version unserer App im iTunes App Store herunterzuladen.

Wenn Sie Ihren Nutzern sichere Anmeldungsmöglichkeiten anbieten möchten (inkl. Finderabdruck Scan und ohne die Verwendung von angreifbaren passwortbasierten Logins) können Sie unsere kostenlose SecSign ID API verwenden, um unsere mobile Zwei-Faktor-Authentifizierung in Ihre App einzubauen. Ebenso können Sie unsere kostenlosen SecSign ID Plugins zur Integration unserer sicheren Anmeldemethode in Ihre Webseite benutzen.

SecSign 2FA