以编程方式检查是不是设置了密码锁
Posted
技术标签:
【中文标题】以编程方式检查是不是设置了密码锁【英文标题】:Programmatically Checking if a Passcode Lock is Set以编程方式检查是否设置了密码锁 【发布时间】:2011-09-05 16:52:07 【问题描述】:由于我的应用会处理用户的敏感数据,我想知道是否有办法从我的应用中检查 ios 中是否设置了密码锁。
我需要检查这一点的原因是,如果用户在应用程序中有一些信息,然后将其保留在桌面上并出去几分钟。 iPad/iPhone 默认进入待机模式。如果设置了密码锁,只有输入正确的密码,任何人都可以使用 ipad。这将提供额外的安全措施,以防止任何路人查看应用程序中的敏感数据。
所以基本上,我希望我的应用程序检查密码锁是否设置,如果没有提示用户这样做。
这可能吗?
【问题讨论】:
我认为不可能。为什么不给你的应用添加一个锁定机制,这样用户就可以在不锁定整个 iPad 的情况下锁定它? 我需要的情况是当用户按住 ipad 并在紧急情况下离开一段时间或其他情况时......那个时候,ipad 会在一段时间后自动锁定(由于它的默认行为)......所以为了防止用户以外的任何人解锁ipad并查看应用程序上的敏感数据,我需要检查是否已为ipad设置密码锁,如果没有,提示用户设置密码锁... 【参考方案1】:在 iOS 8 中,现在可以检查用户是否设置了密码。 此代码将在 iOS 7 上崩溃。
目标-C:
-(BOOL) deviceHasPasscode
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 ;
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
if (status == errSecSuccess) // item added okay, passcode has been set
SecItemDelete((__bridge CFDictionaryRef)attributes);
return true;
return false;
斯威夫特:
func deviceHasPasscode() -> Bool
let secret = "Device has passcode set?".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let attributes = [kSecClass as String:kSecClassGenericPassword, kSecAttrService as String:"LocalDeviceServices", kSecAttrAccount as String:"NoAccount", kSecValueData as String:secret!, kSecAttrAccessible as String:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly]
let status = SecItemAdd(attributes, nil)
if status == 0
SecItemDelete(attributes)
return true
return false
【讨论】:
这是苹果认可的吗? 应该没问题,因为它使用的是标准钥匙串调用。【参考方案2】:由于iOS 9
,LocalAuthentication框架中有一个标志LAPolicyDeviceOwnerAuthentication
。
+ (BOOL)isPasscodeEnabled
NSError *error = nil;
LAContext *context = [[LAContext alloc] init];
BOOL passcodeEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error];
if(passcodeEnabled)
NSLog(@"Passcode enabled.");
return YES;
NSLog(@"Passcode NOT enabled: %@", error.localizedDescription);
return NO;
自iOS 8
以来,还有另一个标志用于检查TouchID
是否启用:
+ (BOOL)isTouchIdEnabled
NSError *error = nil;
LAContext *context = [[LAContext alloc] init];
BOOL touchIDEnabled = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if(touchIDEnabled)
NSLog(@"TouchID enabled.");
return YES;
NSLog(@"TouchID NOT enabled: %@", error.localizedDescription);
return NO;
【讨论】:
【参考方案3】:查看The Application Runtime Environment 上的文件保护部分。文件保护要求用户启用密码锁定设置并设置有效的密码。如果您的应用程序写入/创建并归档,请使用 NSDataWritingFileProtectionComplete 选项。如果您的应用程序不使用任何文件,则创建一个虚拟文件并启用保护。
【讨论】:
如果密码锁被禁用怎么办?您仍然可以手动执行此文件保护锁定吗?我看过 wwdc 2010 关于保护应用程序数据的内容,但它假定您已打开密码锁定。您如何执行此操作? 这不再起作用了。阅读表明它至少从 iOS 5 开始就没有工作过。【参考方案4】:适用于 iOS 8 的 Xamarin.iOS 解决方案...请注意,每次检查时我都会调用 SecKeyChain.Remove(secRecord)
。我发现如果我不包括这个,我可能会让设备进入一个奇怪的状态,它试图在每次调用 SecKeyChain.Add(secRecord)
时向用户进行身份验证
private bool DetectIfPasscodeIsSet ()
var secRecord = new SecRecord (SecKind.GenericPassword)
Label = "Check if passcode is set",
Description = "Check if passcode is set",
Account = "Check if passcode is set",
Service = "Check if passcode is set",
Comment = "Check if passcode is set",
ValueData = NSData.FromString ("Check if passcode is set"),
Generic = NSData.FromString ("Check if passcode is set")
;
SecKeyChain.Remove (secRecord);
secRecord.AccessControl = new SecAccessControl (SecAccessible.WhenPasscodeSetThisDeviceOnly);
var status = SecKeyChain.Add (secRecord);
if (SecStatusCode.Success == status)
SecKeyChain.Remove (secRecord);
return true;
return false;
【讨论】:
谢谢。我需要这个!以上是关于以编程方式检查是不是设置了密码锁的主要内容,如果未能解决你的问题,请参考以下文章
如何在整个时间以编程方式在 Geoserver 上设置用户名和密码