Assume a user enables Touch ID in my app. I need to save this state somewhere. I have two options: NSUserDefaults, and the Keychain.
NSUserDefaults: The problem with storing a boolean fingerprintEnabled in NSUserDefaults is that this flag can be modified. So, an attacker with physical access to the device can simply edit this flag and bypass fingerprint authentication in my app, and gain access to user's secure offline data.
Keychain: This is great, as it is encrypted and cannot be modified externally. However, keychain values are persisted across app installs/uninstalls. If a user uninstalls the app, perhaps because Touch ID isn't working properly, and re-installs it, it will still prompt for Touch ID, even though the new app installation should reset all state.
So where's the best place to store state on whether fingerprint authentication is required?
If you are so concerned about the security of data saved in NSUserDefaults why don't u use the combination of both NSUserDefaults and Keychain
Save a variable in NSUserDefaults lets say installed. This you'll set it to true in AppDelegates didFinishLaunchWithOptions. This you can use as a reference when should you reset the value of fingerprintEnabled in keychain.
Problem with saving it in key chain is you don't know when to reset it. The value in NSUserDefaults now will help you decide when to reset this value.
Because the value in NSUserDefaults will be removed on uninstalling the app, when u uninstall and reinstall the value of installed will be absent in NSUserDefaults now you can go ahead and reset the value of fingerprintEnabled in Keychain if present (Obviously this should be done in didFinishLaunchWithOptions before you set the installed).
On subsequent launches value of installed will prevent you from resetting the value of fingerprintEnabled.
I know this is not the most efficient approach as it uses both NSUserDefaults and KeyChain but solves the problem though.
If using NSUserDefaults is unsafe, using the keychain is unsafe too, so I would use the NSUserDefaults, because it is easier to implement. Let me explain: If the user can just edit the user defaults and get access to the data, this means that the data is unencrypted. (Or at least, it's encrypted in a way that is easy to break if you have access to the source code of the app.) If the data is unencrypted and you use the keychain to store the boolean, the user can as well just patch the binary to omit the keychain-check. Or he may just find the unencrypted payload in the application binary and inspect it.
But now for something more constructive... :) The best way to implement Touch ID protection, is to use Touch ID to unlock a secret key, and encrypting the payload data with that secret key. If Touch ID is disabled, you just use a hardcoded key instead (and use some kind of basic runtime obfuscation, like base64_decode to make it not too easy for attackers.) You can store a boolean in the user defaults (e.g. "data_encryption_enabled")*. If it is YES, you ask the system for the secret key for the "data_access" item. You then decrypt the data with that key (I suggest to use AES128). If "data_encryption_enabled" is NO, you use "9fajw9e8" as the secret key instead. It's easy to see, that if an attacker manages to change "data_encryption_enabled" to NO, this will not unlock the data.
A few more things to consider:
When the payload is saved in a way that it can be backed up to iCloud, you should test if restoring the app from the backup to a different device makes the data unusable. If the data is stored only locally (e.g. either in "Caches", or in "Documents" with NSURLIsExcludedFromBackupKey set to YES/true) this is not an issue.
The algorithm that generates the secret key should be secure. (E.g. use SecRandomCopyBytes)
*) all strings in this example are made up by me, you can choose them however you like.
Related
I need to store a persistent remember token (a string) between app launches and device restarts. The token will be provided by a server once my user logs into the app and its back end service (which is already built). Specifically, I need to set up a persistent data placeholder for the remember token but I don't ever want the code to actually set the value of that placeholder.
On the one hand, it seemed like NSUserDefaults (now called UserDefaults) was a simple way to do this, but after reading the documentation, it doesn't seem like that was the intention of the feature. All the documentation I've see shows setting it up by assigning a value to a key. I definitely don't want to ever have the app assign a value to that key.
What's the simplest way to do this?
The simplest way to achieve that while also taking security into consideration is to use the Keychain. Data stored in the Keychain is encrypted using the key one provides for example when setting the Touch ID support.
You should never, ever, ever, use UserDefaults for such a task. The reason is UserDefaults are backed by the simple, unencrypted .plist file that is a part of your bundle, and can be more or less easily viewed by anyone that can get access to your ipa (e.g. anyone with jailbroken device).
The KeychainAccess API is written in Objective-C, but there are numerous wrappers that encapsulate this using Swift. You can use this on https://github.com/kishikawakatsumi/KeychainAccess
I am working on the app that require protection screen for the app.
This screen looks like :
I already done all features expect one. It is proper saving of the pin code.
I read about iOS Keychain and think it is quite suitable approach to save sensitive information.
But I would like to hear opinion from others is it enough? Or what should i use to protect this (pin code) information.
Now it is working like:
Set
Pin -> Keychain
Get
Keychain -> Pin
Also I consider hashing:
Set
Pin->Encode->Keychain
Get
Keychain->Decode->Pin
Saving a PIN is similar to saving a user password - one should never do this in plain text even when you store it protected like in the keychain.
At least save it as salted hash, better use a password hashing scheme (one-way security function designed for processing passwords and PINs) like PBKDF2, bcrypt, scrypt or Argon.
In most cases the keychain should be enough. But there is no 100 percentage solution. If an attacker has access to the hardware and software you can only make it harder to get the data, not impossible.
That means in your case an attacker already needs access to the device and the device pin code / touchid (if set) to install a jailbreak. Only then it's possible to get access to the content of the keychain and your stored data inside.
An additional encoding of your keychain data requires to store the key for the encode/decode somewhere. You have to save it somewhere else, e.g.in the user defaults, but the keychain already has the highest security level. Encoding makes sense for the real user data (the data you want to secure with the pin: access token, file encryption password, ...), because for these data it may be importend to destroy them in app deinstall/reinstall process. The user defaults will be removed when deinstall, the keychain not.
Scenario: User deletes app and sell his/her phone without resetting it in device settings. Buyer installs jailbreak -> old data in keychain should be garbage/unreadable.
Conclusion:
Think about it: What user data do you wanna secure with the pin? These data are also located inside of the keychain, even if it's only an access token for web requests or a password for an encryption. You don't need a higher security level for the pin than for your data ;)
In case of a pin your solution should be enough. But it's imported that your real user data should use the same security level or a higher one.
Update
There is a higher security level than the keychain: "Secure Enclave". It's mainly used for saving the touch id informations. Apple do not documented it, so I wouldn't recomend to use it yet.
There is a project called Tidas to make it accessible for the community.
I want to store one key value pair very securely in the device. But, I want to persist the data till app in present in the device.
Once app is deleted this data also should get removed.
NSUserdefault is not very secure.
Keychain is another option as it is secure but it persist data even after app will get deleted from the device.
How should I proceed.
Any help?
Create a random encryption key. Store the encryption key in keychain. Encrypt the data with the encryption key. Store the encrypted data wherever is convenient within the app's directories. If you want to preserve it across restores, then store it somewhere that is backed up (such as Library/Application Support or in NSUserDefaults). If you don't want it preserved across restores, store it in Library/Caches (you may need to do some research on that; "the system may delete the Caches directory on rare occasions when the system is very low on disk space" so there is a danger of losing the data, but you had to deal with that in case of restore anyway). You also can use NSURLIsExcludedFromBackupKey to avoid backing it up.
When the app is deleted, the encrypted data will be deleted. You will leave the random key in the keychain, but this is just a random number of no value.
I have used one flag which is stored in keyachain that will set to true whenever app will get launched for the first time.
When my app will get launched for the first time this flag will not present. I will store this flag in keychain with value true and I will store my secure information in the keychain.
If my application is launched for the very first time and flag is present then I will delete the flag and data first and then proceed with step 1.
In this way, I have solved my problem of app is using the already stored data in keychain even after installing and launching for the first time. If user will delete the app, keychain will contain my secure data but that will be of no use as it is encrypted with random key.
I'd appreciate that someone could make it clear some questions I have regarding Data Protection feature:
Is needed/recommended to enable Data Protection to encrypt and protect the SQLite files managed by Core Data? If so, what should I do to encrypt and protect such files?
I followed a tutorial for using Keychain and it said that complete level of Data Protection had to be enabled for the App ID in the Apple Member Center, so that I did. However, it said nothing about also enabling Data Protection in the Xcode's project, so I didn't. It seems that I can access Keychain in my iOS app without problem, but this looks weird... should I also enable Data Protection in the target's settings?
Thanks so much
It depends what you're storing there and thus what is at risk if someone gains access to it. In most cases you don't need to encrypt the data in the DB specifically as someone will use a device lock to secure the device and any specific data that you want to make secure should be stored in the keychain. This is usually the user identifying data and account authentication tokens.
If someone gets access to a device that is unlocked (pin code / touch ID has been cleared or authenticated) then they can do pretty much whatever they want with the device (keychain and automatically encrypted data) and you can't stop them (at best you can slow them down).
Apple does mention you can limit access to Keychain data if someone tries to add their fingerprint after-the-fact. More info in the Keychain section of https://www.apple.com/business/docs/iOS_Security_Guide.pdf
The only thing you can do really is to explicitly encrypt the data which requires it using a key that is explicitly entered by the user each time you need to encrypt / decrypt. That key could be stored in memory temporarily, but you can never write it to disk. In this way the user has to enter the key to use the data and the key can only come from the user.
I would like to store some encryption keys which I use for data transfer in the keychain to keep em safe.
My issue is, how do I keep em safe until I get them into the keychain? If I hard code em into the app, and add them to the keychain on launch the first time, then a hacker would be able to retrieve them by decompiling, any input is highly appreciated.
I would like to add that my validation of the data transfers are also dependent on a user password, which is safely stored in the keychain, but would still like to keep my encryption keys safe.
Thanks.
In 3 words: SSL web service