2010-09-27 2 views
36

Ich schreibe eine iPhone-Anwendung, die ihre Daten verschlüsselt benötigt. Ich habe gelernt, die Verschlüsselung für Dateien zu aktivieren, indem ich das NSFileProtectionComplete-Attribut festlege. Ich weiß auch, wie man die iPhone Version überprüft, um sicherzustellen, dass sie iOS 4.0 oder besser laufen.Wie kann ich herausfinden, ob der iPhone-Benutzer derzeit einen Passcode hat und die Verschlüsselung aktiviert ist?

Was ich jedoch festgestellt habe, dass, wenn der Benutzer keinen Passcode gewählt hat und nicht speziell den Datenschutz auf dem Bildschirm Einstellungen> Allgemein> Passcode sperren aktiviert hat, sind die Daten überhaupt nicht geschützt.

Ich möchte eine Warnung ausgeben und dem Benutzer mitteilen, dass er einen Zugangscode aktivieren und den Datenschutz einschalten muss (was ein Backup und eine Wiederherstellung auf iPhones erfordert) und dann die Anwendung beenden Passcode und Datenschutz nicht aktiviert Ich kann es sowieso nicht herausfinden, um den Zustand dieser Einstellungen herauszufinden. Alle APIs, die ich gefunden habe, wie "protectedDataAvailable" in UIApplication, werden alle erfolgreich ausgeführt, wenn der Datenschutz deaktiviert ist.

+0

Ich würde davon ausgehen, dass die Passcode-Sperre für die laufende Anwendung irrelevant ist, also denke ich, es ist nicht Teil des SDK. Wenn es wäre, wäre es wahrscheinlich Teil dieser API: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html –

+2

Es ist extrem relevant für eine laufende Anwendung, weil Ohne Passwort sind Ihre Daten auf dem Gerät nicht geschützt. Es wäre ein großes Versehen von Apple, wenn es nicht möglich wäre zu sagen, ob Ihre Daten geschützt sind oder nicht. Es macht die neue iOS 4-Verschlüsselung für die meisten Unternehmensanwendungen, die über den App Store verkauft werden, ziemlich nutzlos. – Mike

+3

Die meisten Unternehmen hätten (sollten) ein Bereitstellungsprofil, das an alle iPhones der Firma gesendet wird, um den Zugangscode zu verlangen. Dies ist kein Programmproblem, dies ist ein Managementproblem. Sie möchten wirklich eine Warnung ausgeben, die dem Benutzer sagt, dass er seinen Zugangscode aktivieren soll? Oder noch besser, weigere dich zu laufen, wenn es nicht läuft? Benutzer nehmen normalerweise nicht gut zu sagen, was mit ihren Geräten zu tun ist. –

Antwort

18

Haftungsausschluss: Diese Antwort war gültig bis ios 4.3.3

Wenn Schutzdaten eingeschaltet ist, eine neu erstellte Datei eine nilNSFileProtectionKey standardmäßig haben wird.

Wenn der Datenschutz deaktiviert ist, hat eine neu erstellte Datei standardmäßig eine NSFileProtectionNone .

So könnte man das Vorhandensein von Dateischutz mit dem folgenden Code ermitteln:

NSString *tmpDirectoryPath = 
    [NSHomeDirectory() stringByAppendingPathComponent:@"tmp"]; 
NSString *testFilePath = 
    [tmpDirectoryPath stringByAppendingPathComponent:@"testFile"]; 
[@"" writeToFile:testFilePath 
     atomically:YES 
     encoding:NSUTF8StringEncoding 
      error:NULL]; // obviously, do better error handling 
NSDictionary *testFileAttributes = 
    [[NSFileManager defaultManager] attributesOfItemAtPath:testFile1Path 
                error:NULL]; 
BOOL fileProtectionEnabled = 
    [NSFileProtectionNone isEqualToString:[testFile1Attributes objectForKey:NSFileProtectionKey]]; 
+0

das half .. vielen Dank für die Mühe, den Code zu schreiben .. – learner2010

+0

danke für die Zeit nehmen, um tatsächlich die Frage zu lesen. ausgezeichnete Antwort –

+1

Sind Sie sicher, dass dies funktioniert? Ich teste gerade im Moment mit einem iPad (4.3.5) und das Attribut ist immer NSFIleProtectionNone ... "Data Protection is enabled" taucht in den Keycode-Einstellungen auf .... –

1

Unabhängig NSDataWritingAtomic oder NSDataWritingFileProtectionComplete, Ergebnis ist immer das gleiche für mich. Seltsames Verhalten, hier ist der Code:

BOOL expandTilde = YES; 
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, expandTilde); 
NSString *filePath; 
filePath = [[paths lastObject] stringByAppendingPathComponent:@"passcode-check"]; 

NSMutableData *testData; 
testData = [NSMutableData dataWithLength:1024]; 

NSLog(@"Attempt to write data of length %u file: %@", [testData length], filePath); 

NSError *error = nil; 

if (![testData writeToFile:filePath options:NSDataWritingAtomic error:&error]) { 
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    return NO; 
} else { 
    NSLog(@"File write successful."); 

    error = nil; 
    NSDictionary *testFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; 

    NSLog(@"Getting attributes: %@", testFileAttributes); 

    if ([NSFileProtectionComplete isEqualToString:[testFileAttributes objectForKey:NSFileProtectionKey]]) { 
     error = nil; 
     [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; 
     // passcode disabled 
     return YES; 
    } else { 
     error = nil; 
     [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; 
     return NO; 
    } 

} 
+2

Übrigens hat die Find Friends App diese Funktionalität. Es fordert nur dann erneut ein Passwort an, wenn das Gerät nicht passwortgeschützt ist. – igraczech

+0

Hallo, Ich habe den Link überprüft, aber jedes Mal, wenn es den gleichen Wert zurückgibt NSFileProtectionKey = NSFileProtectionNone; – Suchi

3

Apple stellt keine Methode zur Verfügung, um festzustellen, ob der Benutzer einen Sicherheitscode festgelegt hat.

Wenn Ihre App verschlüsselt werden muss, sollten Sie die Dateien mit einer vertrauenswürdigen Verschlüsselungsimplementierung verschlüsseln und entschlüsseln und den Benutzer entweder nach einem Passcode fragen oder den Schlüssel im Schlüsselbund speichern.

13

iOS 8 (OS X Yosemite) führte eine neue API/Konstante ein, um festzustellen, ob das Gerät eines Benutzers über einen Passcode verfügt.

kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly kann verwendet werden, um zu erkennen, ob auf dem Gerät ein Passcode festgelegt wurde.

Die Strömung ist:

  1. Versuch mit diesem Attribut ein neues Element auf dem Schlüsselbund zu speichern gesetzt
  2. Wenn es gelingt, dass anzeigt, dass ein Zugangscode zur Zeit
  3. aktiviert ist Wenn das Passwort nicht der Fall ist gespeichert werden, zeigt an, dass es keinen Passcode gibt
  4. Bereinigen Sie das Element, denn wenn es bereits auf dem Schlüsselbund ist, wird ein "Hinzufügen" fehlschlagen, es sieht so aus, als wäre der Passcode nicht gesetzt

Ich habe dies auf meinem iPhone 5S getestet, zuerst gab es true zurück, dann deaktivierte ich den Passcode in den Einstellungen, und es gab false zurück.Schließlich habe ich den Passcode erneut aktiviert und gibt true zurück. Frühere Betriebssystemversionen geben false zurück. Der Code funktioniert im Simulator und gibt true auf einem Computer zurück, auf dem das OS X-Kennwort festgelegt ist (ich habe keine alternativen OS X-Szenarien getestet).

Auch hier sehen Beispielprojekt: https://github.com/project-imas/passcode-check/pull/5

Schließlich meines Wissens iOS 8 nicht über eine Einstellung des Datenschutzes zu deaktivieren, so dass ich davon ausgehen, das alles, was Sie brauchen, ist die Verschlüsselung zu gewährleisten.

BOOL isAPIAvailable = (&kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly != NULL); 

// Not available prior to iOS 8 - safe to return false rather than crashing 
if(isAPIAvailable) { 

    // From http://pastebin.com/T9YwEjnL 
    NSData* secret = [@"Device has passcode set?" dataUsingEncoding:NSUTF8StringEncoding]; 
    NSDictionary *attributes = @{ 
     (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, 
     (__bridge id)kSecAttrService: @"LocalDeviceServices", 
     (__bridge id)kSecAttrAccount: @"NoAccount", 
     (__bridge id)kSecValueData: secret, 
     (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly 
    }; 

    // Original code claimed to check if the item was already on the keychain 
    // but in reality you can't add duplicates so this will fail with errSecDuplicateItem 
    // if the item is already on the keychain (which could throw off our check if 
    // kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly was not set) 

    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL); 
    if (status == errSecSuccess) { // item added okay, passcode has been set 
     NSDictionary *query = @{ 
      (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, 
      (__bridge id)kSecAttrService: @"LocalDeviceServices", 
      (__bridge id)kSecAttrAccount: @"NoAccount" 
     }; 

     status = SecItemDelete((__bridge CFDictionaryRef)query); 

     return true; 
    } 

    // errSecDecode seems to be the error thrown on a device with no passcode set 
    if (status == errSecDecode) { 
     return false; 
    } 
} 

return false; 

P.S. Wie Apple in dem WWDC-Video (711 Keychain und Authentifizierung mit Touch ID) hervorhebt, haben sie den Passcode-Status nicht absichtlich direkt über die API verfügbar gemacht, um zu verhindern, dass Apps in Situationen kommen, die sie nicht sein sollten ("Hat dieses Gerät einen Passcode? Okay, großartig, ich werde diese privaten Informationen im Klartext speichern.") Es wäre viel besser, einen Verschlüsselungsschlüssel zu erstellen, ihn unter kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly zu speichern und diese Datei zu verschlüsseln, die nicht wiederhergestellt werden kann wenn ein Benutzer sich entscheidet, seinen Passcode zu deaktivieren).

+0

ist dies von Apple genehmigt? – Nil

+0

Ich habe noch nie eine App eingereicht, die es verwendet, aber alle Funktionen sind dokumentiert (keine privaten APIs), also nehme ich an, dass es sein wird. – owenfi

0

Da IOS 9, gibt es ein Flag LAPolicyDeviceOwnerAuthentication in LocalAuthentication Rahmen.

+ (BOOL)isPasscodeEnabled 
{ 
    NSError *error = nil; 
    LAContext *context = [[LAContext alloc] init]; 

    BOOL passcodeEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]; 

    if(passcodeEnabled) { 
     return YES; 
    } 

    return NO; 
} 
0

Swift 3

func isPasscodeEnabled() -> Bool { 
    return LAContext().canEvaluatePolicy(LAPolicy.deviceOwnerAuthentica‌​tion, error:nil) 
} 

IOS 9 oder höher erforderlich.