Currently i have an application which has a "Remember Me" option for storing User ID.So to store this currently i am using Keychain APIs.
But i have a doubt if by chance device is stolen and somebody jailbreak the device. Can he able to get all these data from keychain?
How to prevent this ?
The most important thing when using the KeyChain is to not use kSecAttrAccessibleAlways or kSecAttrAccessibleAlwaysThisDeviceOnly because then data is not encrypted securely (see Apple's documentation). Not using these adds a layer of security to KeyChain data, but still, a strong passcode would be required by the user to protect his data. If the user has no passcode on the device, the data is unprotected. If the user has a 4-digit passcode (the standard), the data is protected very weakly and can be brute forced in minutes.
If you require protection from jailbreak (and other attacks), your best option is to not use the KeyChain, but create an encrypted sensitive data store of your own and require the user to have a secure passcode. Store the data encrypted using a key generated from that passcode.
This could inconvenience your users, so if you wish to provide a grace period between requiring passcode, think of a way to provide a session cookie to the app which is invalidated after a set period of time.
To be extra safe I'd add another layer of security on top of everything and make a simple check if the device is jailbroken. If that's the case I'd delete the current KeyChain \ sensitive data.
Something like that:
NSString *filePath = #"/Applications/Cydia.app";
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
//Device is jailbroken --> delete KeyChain
}
Or even better:
FILE *f = fopen("/bin/bash", "r");
BOOL isbash = NO;
if (f != NULL)
{
//Device is jailbroken --> delete KeyChain
isbash = YES;
}
fclose(f);
Here is the best way for checking if Device jailbroken
Code that checks
bool forked = fork();
if (forked) {
// Device is jailbroken
}
Check this link Keychain Items, where you can enumerate all keychain items.
You can also use Protection Attributes for securing info.
Apple Docs
Good Read
Related
This happens on iOS 13.3 (iPhone 11)
I developed a react native iOS app which saves/loads data into/from keychain via https://github.com/mCodex/react-native-sensitive-info/blob/master/ios/RNSensitiveInfo/RNSensitiveInfo.m
My read/write keychain options is below, it never changes and works well since day1
const defaultOptions: RNSensitiveInfoOptions = {
touchID: true,
kSecAccessControl: 'kSecAccessControlBiometryAny',
kSecUseOperationPrompt: 'We will store data securely on your device.',
sharedPreferencesName: 'sensitive',
keychainService: 'sensitive',
};
Recently one of my clients complain about the data cannot be retrieved from keychain because of errSecNotAvailable = -25291, /* No keychain is available. You may need to restart your computer. */
I thought there might be something wrong happened to keychain, so I tried set a single key/value item with the same option (so the kSecAttrService and kSecClass are same with business related items): 'foo' -> 'bar'. And I can load this value out via the same option.
I did more experiences:
if I read a key doesn't exist, the keychain API will return error errSecItemNotFound -25300
if I read a business related key, the keychain API return error errSecNotAvailable -25291
I jailbreak this iPhone and use https://github.com/ptoomey3/Keychain-Dumper to dump the items but it prompt (although the phone is unlock):
[INFO] No Generic Password Keychain items found.
[HINT] You should unlock your device!
I copied Keychain-2.db from device to local computer and using sqlite DB to query the generic password items, looks like they are there (but as they are encrypted, i am not sure 100%):
I am expecting someone could suggest:
why this issue could happen?
is there any possibility I can restore the keychain data?
I am using SecItemCopyMatching to fetch a keychain item protected by Touch ID.
However, if Touch ID unlocking fails (or the user selects "Enter Passcode"), I want to present my own PIN-entry UI.
I do not want the user to be presented with the system passcode entry UI at any point.
LAContext's evaluatePolicy method provides this, but does not offer any actual keychain security, merely local authentication.
I therefore will not use LAContext to achieve this. Is this possible with SecItemCopyMatching?
On iOS 8.3 and above, the passcode fallback option is hidden initially but still appears if the first finger presented is not recognised.
For iOS 9, two new policies have been added that do not fallback to passcode. These policies are kSecAccessControlTouchIDAny and kSecAccessControlTouchIDCurrentSet
We had similar dilemma while working on one of our in-production app. We realised that we need touch ID unlock as well as custom fallback mechanism (which requires server API for unlocking) which is stronger than 4 digit unlock password.
So, Let me try to explain how we achieve it.
Similar is expectedly done by Apple for Appstore purchase and 1Password app.
Background:
Two mechanisms to integrate Touch ID:
Use Touch ID to access credentials stored in the keychain
Issue:
If a device has Touch ID as well, the preferred method is to authenticate with Touch ID and passcode is the backup mechanism
No other fallback mechanism is permitted and Apple does not allow customisation of the fallback user interface
Use Touch ID to authenticate with the app directly (called Local Authentication)
Issue:
No permission is granted to store secrets into or retrieve secrets from the Secure Enclave
Contrary to the keychain access case, Apple does not allow device passcode authentication as a backup
Every application needs to provide its own fallback to handle failed Touch ID case with custom UI
Concern:
About storing sensitive information in the keychain:
We were tempted to use this approach but were taken aback by realising the only fallback for failing to authenticate with Touch ID is the device passcode. iOS users usually configure a four digit passcode, which is less secure than users custom passwords.
Facelifting examples:
Apple uses your iCloud account password [custom fallback mechanism] as a fallback mechanism for itunes store purchase if user fails to authenticate with Touch ID.
1Password app also has similar approach.
Conclusion
In our app we authenticate with Touch ID via LocalAuthentication, we use our 'app specific PIN unlock feature' or the client's password as the fallback mechanism.
We don't store the password on the device, failure to authenticate with Touch ID requires full authentication through servers API, if device does not have a PIN configured within app.
Sample code:
[self.laContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:reason
reply:^(BOOL success, NSError *error) {
if (success)
dispatch_async(dispatch_get_main_queue(), ^{ successBlock(); });
else
dispatch_async(dispatch_get_main_queue(), ^{ fallbackBlock(error); });
self.laContext = nil;
}
];
This should probably be a comment to bllakjakk, but my reputation does not allow me to do so yet.
I am only adding this answer because the question was specifically asking about:
fetch a keychain item protected by Touch ID
The accepted answer mentions a scenario where no credentials are stored on the device.
For completeness I wanted to mention that if your app needs to authenticate to some external entity, and you therefore have to store credentials somewhere, then the Key-Chain option is the one to consider over Local Authentication.
The fear of somebody being able to authenticate via fallback for Key-Chain if they know the device pass-code (potentially weak four-digit and so on) is a moot point because nothing keeps a user from adding their own fingerprint to the device if they possess the pass-code, and then authenticating via Key-Chain or Local Authentication without having to select the fallback.
So if you are using Local Authentication over Key-Chain because you feel that the fallback mechanism is safer, you might be overlooking that minor detail and therefore be passing up on the opportunity to store credentials in the secure enclave.
We are about to implement TouchID for a financial application and are opting for Key-Chain. The intent is to educate our users about the need for strong device pass-codes at the time when they try to enable TouchID for our app.
I hope this helps you in making a decision.
You can try hiding the Enter Password button by doing the following:
1) define global function
static bool new_isFallbackButtonVisible(id self, SEL _cmd)
{
return NO;
}
2) in your application:didFinishLaunchingWithOptions: replace isFallbackButtonVisible method of LAContext class with your new implementation by calling
class_replaceMethod(NSClassFromString(#"LAContext"), NSSelectorFromString(#"isFallbackButtonVisible"), (IMP)new_isFallbackButtonVisible, "v#:B");
There is no way to disable fallback mechanism using passcode in Keychain TouchID integration. Use LocalAuthentication instead (But LocalAuthentication just provides a TouchID auth UI though not related to the Keychain).
You can hide/customize the "Enter Password" option by setting:
LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = #"";
and the option will disappear, or:
LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = #"Disable TouchID";
to customize the option text. While I know this isn't exactly what the OP was asking, it's most certainly related and could "fallback" into wanting minds.
I'm trying to determine the best way for me to store, and access an Access token in use of an iOS app.
I'm getting myself familiar with Core data, and while this has proved beneficial for some parts of the app's data, i'm not sure core data is best for what i need for the token.
Most views rely on some simple network request to our API. The access token is used with these requests to authenticate and authorize the data content requested.
To explain better here, an example of how it would be used is within the AppDelegate.m. on applicaion:hasFinishedLoadingWithOptions i preform a simple check to confirm the token with the API, on success the view is changed to the 'main menu', and on failure, view is changed to the login view.
This token needs to be accessed in most views as at any point the API voids the token, the user will have to re-login to attain a new token (not regularly).
My intial thought is to impement a token.h which i can call in ViewControllers where needed, however as this is my first large iOS app i would feel better with some constructive critism, tips or hints about how best to access this token, 'globally' as if it were a static value
You can store it in keychain like this
Apple has written an Objective-C wrapper that you can use to simplify working with the keychain, the files in the wrapper are KeychainItemWrapper.h and KeychainItemWrapper.m, both are included in the attached Xcode project.
UITextField *accesstoken = [[UITextField alloc] initWithFrame:CGRectMake(40, 30, 240, 30)];
[accesstoken setBorderStyle:UITextBorderStyleRoundedRect];
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:#"TestAppLoginData" accessGroup:nil];
Writing to the Keychain-
// Store AcessToken to keychain
Nsstring *strAcessToken=#"abcd"
[keychain setObject:strAcessToken forKey:(id)kSecAttrAccount];
Reading from the Keychain-
// Get AcessToken from keychain (if it exists)
[accesstoken setText:[keychain objectForKey:(id)kSecAttrAccount]];
Notes:
Writing and retrieving values from the keychain doesn’t seem to work in the simulator.
Uninstalling an application will not remove the items from the keychain. If you run the demo application on your device, and uninstall the app, the username and password will remain in the keychain (a firmware reset will, of course, remove the keychain values).
Although is question is highly drawn to have only opinionated answer I will give my point of view on the subject.
You need an API client, which hold the acces token, every time an new view controller is create it should get a reference to this API client. Or if you are not comfortable with pass it every time you might implement the API client a singleton.
All server API class should be via this API client, which should handle the network and API calls.
AFNetworking is great example of how this can be done.
The access token it self should be stored in the keychain, because this is the place to stored these kind of thing.
You can store your token in the NSUserDefaults
+(void)saveToken:(NSString *)token{
[[NSUserDefaults standardUserDefaults] setObject:token forKey:#"token"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
+(NSString *)getToken{
return [[NSUserDefaults standardUserDefaults] objectForKey:#"token"];
}
I need to securely store/retrieve items on iOS keychain.
From Apple KeyChainServicesReference doc (https://developer.apple.com/library/ios/documentation/security/Reference/keychainservices/Reference/reference.html) I retrieve keychain items using SecItemCopyMatching call. The latter pops up a system prompt for authenticating against local keychain that allows using fingerprint or, alternatively, a 4-digit phone passcode.
While I consider auth with fingerprint secure, it's that 4 digit PIN option that downgrades my current security. So, my question is: is there a way to query keychain with just fingerprint option (no passcode option and if fingerprint auth fails, it just fails, no fallbacks to 4 digit passcode)
I have looked into LocalAuthentication and although the latter provides the exact flow that I need, LA doesn't give me access to the keychain and thus LA is of no use to me
Thanks a lot in advance
In LAContext.h:
/// Fallback button title.
/// #discussion Allows fallback button title customization. A default title "Enter Password" is used when
/// this property is left nil. If set to empty string, the button will be hidden.
#property (nonatomic, copy) NSString *localizedFallbackTitle;
This code removes the button and user can either use their finger or cancel:
LAContext *context = [[LAContext alloc] init];
context.localizedFallbackTitle = #"";
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics ...
You're right, in iOS 8 you have no option to store an item in Keychain and make it accessible only after successful Touch ID authentication. The kSecAccessControlUserPresence access control flag added in iOS 8 makes an item accessible after either Touch ID or Passcode authentication.
But this can now be done in iOS 9. Two Touch ID-related flags, kSecAccessControlTouchIDAny and kSecAccessControlTouchIDCurrentSet, have been added.
So, all you need to do is use either of these two flags when creating access control object for Keychain item (with SecAccessControlCreateWithFlags function), and assign that object to kSecAttrAccessControl attribute when adding the item with SecItemAdd function.
There is an example from Apple that demonstrates this; see addTouchIDItemAsync method.
Also see this post for an overview of other security-related changes in iOS 9.
I haven't dived into iOS 8 keychain yet, but remember that the 4-digit passcode is set by a user. Apple recommends that when users turn on TouchID, they also turn on a more complex password, saying "Since security is only as secure as its weakest point, you can choose to increase the security of a 4-digit passcode by using a complex alphanumeric passcode." http://support.apple.com/kb/HT5949
So, the user still has the option of using something more complex than a 4-digit passcode. You just can't force them to do it. If you really want to force them, it sounds like you have to abandon the convenience of Touch ID.
I am developing a location based Q&A SDK for mobile devices.
When a question is asked about a specific location, the server side targets the most relevant user and sends the question to that user. If the user fails to answer, the question is sent to the second best user, and so on.
The problem is that my SDK might be installed on more than one application on the device, meaning that the user can get a question more than once.
Is there a way to detect whether my SDK is installed on more than one app? I thought that sending the UDID to the server might work, but iOS UDIDs differ between applications.
You can use UIPasteboard to share data between applications on the device.
The UIPasteboard class enables an app to share data within the app and with another app. To share data with any other app, you can use system-wide pasteboards; to share data with another app that has the same team ID as your app, you can use app-specific pasteboards.
In your SDK, do something like this:
#interface SDKDetector : NSObject
#end
#implementation SDKDetector
+ (void)load
{
int numberOfApps = (int)[self numberOfAppsInDeviceUsingSDK];
NSLog(#"Number of apps using sdk:%d", numberOfApps);
}
+ (NSInteger)numberOfAppsInDeviceUsingSDK
{
static NSString *pasteboardType = #"mySDKPasteboardUniqueKey";
NSData *value = [[UIPasteboard generalPasteboard] valueForPasteboardType:pasteboardType];
NSMutableArray *storedData = [[NSKeyedUnarchiver unarchiveObjectWithData:value] mutableCopy];
if (!storedData) {
storedData = [NSMutableArray new];
}
NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier];
if (![storedData containsObject:bundleId]) {
[storedData addObject:[[NSBundle mainBundle] bundleIdentifier]];
}
value = [NSKeyedArchiver archivedDataWithRootObject:storedData];
[[UIPasteboard generalPasteboard] setData:value forPasteboardType:pasteboardType];
return [storedData count];
}
#end
If you only want to provide an SDK, it is not possible. Apple has added security steps to prevent that for user privacy. Keychain sharing will not work, because apps must share the same bundle seed ID (see here for more info).
If you want to provide an app along with your SDK, then you could do something like Facebook does, where app sends a "helo" message, Facebook asks user and finally Facebook sends "ehlo" message.
Your App -> "I would like to use the SDK; please give me token" -> SDK Controller App -> (Remember which apps have requested use) -> "OK, you can use the SDK; here is a token: #123" -> Your App
The SDK controller app can now send the server the list of apps.
I think you can group the apps on the same device by IP address as they will use the same address to connect to your server.
So the IP address will represent the device and the API key will represent the app that uses the SDK.
Can you try using
advertisingIdentifier
Not sure whether it serves your purpose. It is explained in here ASIdentifierManager class reference : Apple doc
I think its possible using keychain, you can have an unique keychain key in which you can save anything you want, and can be accessed by other apps if available. So for your SDK, lets say if there is one app, it will register some value in keychain with a unique key which is private to your SDK only if the key doesn't exist, and if it exist you get to know, since you can save any value in keychain, you can try multiple options and combinations which suits you.
You can use KeychainItemWrapper for the implementations.
Elaboration
Lets say we have an method.
[MySDK register];
Which can be used anywhere, say in AppDelegate. The register method will generate a token for the app, for the device, which we will save in the keychain using an unique key we have defined in the SDK, say in com.mysdk.key. And while saving in keychain the SDK can actually do a registration.
We consider the above method is implemented in multiple apps.
Now we have scenario.
User installs an App-A which uses the SDK, the register method will call and create a token and will save in keychain for the first time.
Now user installs another App-B which also uses the SDK, the same register method will call, but now it will check for the key com.mysdk.key in keychain, if exist it will just update the count for the token, which meant for the device.
Note
Keychain not meant to save only unique identifier, you can save other informations too.
Update
Check demo projects https://db.tt/7xpKrgMp
The wrapper I have used in the projects is same as SDK in your case which is same in both the projects.
Cheers.