Using an Encrypted Realm in a background or notification processes? - ios

Realm has a great write up and sample code for encrypting your database. This documentation and sample work as intended, until you try to decrypt realm when:
A user has a password on their phone
The device is locked
Your app is trying to do work with Realm when a remote notification comes in
This happens because we can't access the keychain to get (or create) the key to en/decrypt the Realm. The default kSecAttrAccessible value is kSecAttrAccessibleWhenUnlocked
There are a few options as I see them:
Change kSecAttrAccessible to kSecAttrAccessibleAlways. I don't like this because it's a) too open and b) it was slated to be deprecated in iOS 9
Change kSecAttrAccessible to kSecAttrAccessibleAfterFirstUnlock or kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. This is better but still feels too open to me, even though the docs state: This is recommended for items that need to be accessed by background applications
Create a second, non-encrypted Realm to use as a staging database. Store notification data here, then when the app wakes up from user interaction (the device would be unlocked), move the data from the staging Realm into the encrypted real one. This doesn't feel right either, as we'll have data temporarily not encrypted
Combine 2 and 3 and encrypt the staging Realm, and protect it's key with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
??
I'm currently trying to decide if #2, if #3 is worth putting the time into, or if I can come up with a #5
Is there an approach here that I clearly should use or one I've missed?
Thanks

I'm an author of KeychainAccess library. I strong recommend you to use kSecAttrAccessibleAfterFirstUnlock (The 2nd option). It is the best way to access keychain items from the background.

Related

iOS: Are there any pitfalls using keychain to save data

I am saving an important key in the iOS keychain. Everything seems to be working okay right now. There has only been only one issue. The keychain data is still alive after you delete the App. Which I was able to resolve by checking if the App has just been installed and deleting the data in the keychain. However, I want to be sure if there isn't any more issues or pitfalls I should be looking for.
The Apple keychain uses 256 bit AES encryption to secure data. It is ostensibly the mechanism that Apple uses internally to store private data such as your passwords as well. Other than your comment about the data being persisted after you delete your app (which is a feature not a bug), there’s not going to a “gotcha” when using the keychain API. Just realize that the keychain is just a fancy encrypted database, and follow best practices for what you should store, and when you access / write to it, like any other DB.

Best way in iOS and Swift to store a server-supplied credential between app launches

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

How to store critically sensitive information such as secret, key, token, encryptionKey in iOS application

When we talk about securing iOS application we often forget to secure most critically sensitive information such as secret, key, token, encryptionKey. This information is stored in iOS binary. So none of your server side security protocol will help you.
There are lots of suggestion that we should not store such information in the app but store in the server and get it via SSL secured web service call. But this is not possible for all application. E.g. if my application does not need web service at all.
In iOS app we have following option to store information.
UserDefault: Not appropriate for this case
String Constant: Not appropriate for this case. Can be reverse
engineer to retrieve or just use strings command
Secure Database: Store in Secure and encrypted Database. But again have responsibility to secure database username and password.
KeyChain: Best to store critical info. But we cannot save information before installing the app. To store in the keychain, we first need to open the app, read from some source and store in the keychain. Not appropriate for our case either.
Custom Hash String Constant: Not to directly use secret, token, key from service provider (mixpanel, paypal), instead use hash version of that information from custom key. This is also not perfect solution. But add complexity during hacking.
Kindly send some awsome solution to this problem.
If you don't want to use your own backend then use Apple. You can configure On Demand Resources and keep data file with your key, token, any secret on Apple server. After first download you can write this data to Keychain which is secure enough. I'm guessing networking between iOS and Apple server is also secure enough.
On-Demand Resources Essentials
Accessing and Downloading On-Demand Resources
1) Internet Connection Required
1.1) Push Notifications
Great way to have a secure data exchange could be to use (silent) push services from Apple, those use the apns and send data through https - more Details 3.1
1.2)
A more or less similar approach is also used when distributing new user certificates to already deployed applications, if a reinstall of the application is no opportunity AND the application requires a working internet connection anyway.
Downside: working network connection required and basically the information is coming to the application, when it is already being executed => seems not to be appropriate for your case. (see step 4)
2) Static data (as there will be no exchange without network connection / communication partner)
Encryption of data with private key being provided in the bundle itself. Whether it is now a string or a hash, which can be reverse engineered with functions you got emebedded in your application.
Since iOS9 it is pretty hard to decompile iOS applications and basically you will mainly have a look into the provided header-files. So if you had such a function, string, hash value or whatever, make sure you got it in your .m-file!
But again: if the information is not device or user specific, just a secret across your own micro environment, valid across all devices, you would have to provide the encrypted data AND the decryption method in the same bundle, if there is no update process / information exchange or something else, you can think of.
Good for encryption:
iOS System.Security https://developer.apple.com/reference/security
or simply openssl
The difference between your described keychain approach is:
You got a value, which WILL be encrypted and stored securely.
(2) describes the approach to have an encrypted and stored (in bundle) semi secure value, which WILL be decrypted
3) Information exchange
You describe critical data, which was hashed by another instance. Great! - Make sure, relly make sure, the instance you are talking to is really the instance you expect to be (Network Hooking prevention with ssl certificate pinning etc, but even here you might have intruder (men-in-the-middle)). And you will (probably) have a certificate being provided in your application bundle, to ensure the authenticity of the communication server - here you go again, data that is supposed to ensure a secure process between certain instances of your micro environment. Nevertheless, this data is being provided in your application's bundle.
3.1 Secure Information Exchange extended - Silent Push
Make use of Apple's servers to exchange your secrets for this purpose. If you just need to exchange small data chunks. I would recommend to use silent push notifications to the user, those do even work without explicit permission from the user. Huge advantage: In case your secrets or keys change, you can inform users as soon as possible about the change. They will likely only need the change, when they receive new data, which should reliably work in most cases. Exception: Data exchange in local networks or via bluetooth, in this case I would recommend to provide a notification to the user to have the requirement to update a local decryption key. Or exchange the key in this format as well. Once again: I am leaking some detailed information about your environment architecture.
Downside: You don't know, whether a user just used your app for the first time, until the user "tells" you so.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
3.1 Secure Information Exchange extended - In App Purchase
Use a frree In-App Purchase for the user to get the data to your phone. Good point here: you can provide larger data chunks easily, as this should be an active request by the user, the user does expect certain processing time and should also be aware of the fact to require a working internet connection.
Downside: User would have to select this on purpose. Up until then the app would not work accordinly.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267
So, it just slightly differs from the approach (2) in its basic idea.
In short: Can you provide additional information, what kind of data you need to encrypt/want to store securely and whether you will have a network exchange or not?
Would need some more information here :-)
I would like to emphasize once again that an application on iOS is not that easy to decrypt anymore, even decompiling would not get everything, you expect it to get. For instance decryption tools like dumpdecrypt were only working properly up until iOS 8.4
It seems to me that the best way to do this is using the built in CloudKit. You can save your secrets in the CloudKit Dashboard and then fetch them on startup. Since CloudKit is only a transport layer you'll have to store the app secrets in the KeyChain.
I know you mentioned the KeyChain not being ideal for your use case (not sure why), but this is a good way of not including the secrets in your app. You can't get around fetching your app secrets from another source.
CloudKit access is secured using the system iCloud account and if there is no iCloud account you still access the iCloud servers securely. Another added benefit of this is that you can change your app secrets at any time, so if you want to be even more secure you can implement a rotation schedule.
Learn more about CloudKit
Cocoapods-keys might be a best option.
From cocoapods-keys doc's
Key names are stored in ~/.cocoapods/keys/ and key values in the OS X
keychain. When you run pod install or pod update, an Objective-C class
is created with scrambled versions of the keys, making it difficult to
just dump the contents of the decrypted binary and extract the keys.
At runtime, the keys are unscrambled for use in your app.
The generated Objective-C classes are stored in the Pods/CocoaPodsKeys
directory, so if you're checking in your Pods folder, just add
Pods/CocoaPodsKeys to your .gitignore file. CocoaPods-Keys supports
integration in Swift or Objective-C projects.
Check out this link for installation, usage and more info : https://github.com/orta/cocoapods-keys
I agree with #Lobsterman and believe that the best way will be to use a combination of these.
Don't include the secret information in the app initially.
Deliver the secret key either as in-App purchase content ,on-demand resource or send it through push notification. This will add the benefit of changing the key periodically if you want and the change will take effect without any additional effort.
Add the entry to keychain access once the content is delivered.
If the data is extremely sensitive then it should never be stored offline on device because all devices are crackable. If you still want to store on device then keychain is one option for storing data securely, However it's encryption is based on the pin code of the device. User's are not forced to set a pin, so in some situations the data may not even be encrypted. In addition the users pin code may be easily hacked.
A better solution is to use something like SQLCipher which is a fully encrypted SQLite database. The encryption key can be enforced by the application and separate from the user's pin code.

keep corporate app alive in background

I am developing a corporate app that will be publish on an internal store.
The app is just supposed to keep in memory some credentials but I can't store them on the device for security reasons.
I want the app to stay in background as long as possible but I don't know what is the best solution knowing that I won't have to publish the app in the AppStore.
I read about the option in plist Required background modes, but I don't know which option is the most efficient for my situation.
Firstly, you don't need to keep running app in background, second you can store "those [secret] credentials" in keychain store with some encrypted format, SHA1 or MD5 or any other cryptographic hash functions can be use for this, third the benefit of this is you can access to them from your different apps as well (by using the same encryption key to decryption and accessing keychain store item), at last when you no longer need it, you can even delete it. The only thing you need to keep secret is keychain store key (which you used to store credentials) and also your encryption key (to used with cryptographic hash function).
There's are several libraries available to easily manipulate data in keychain store, here's the one, and here's the solution to apply MD5 or SHA1.

iOS: Storing user registration details

I an building my first iOS application and I need to store the user registration details of the user using the application. The details include his mobile number and a unique id( uuid ) which I use to contact with the backend. It would be great if I could get a suggestion on where to store this user details.
Should I be storing this in the NSUserDefaults or should I be using Keychains to store this data or even may be a using a user model in the database ( I would need a database in any case to store a few other details ). Just to add on, I also would like to perform a few validations like if the mobile number is of proper format and so on before I could actually save it. Also can any one please suggest on the security aspects of different storage mechanisms possible here?
Any help on this would be much appreciated.
The most secure way would be to use keychain services as the data is encrypted but in your scenario it seems a bit over kill. I would recommend either just using NSUserDefaults or an sqlite database I wouldn't really recommend storing in a plist as this can be accessed really easily.
But this all depends on the data you are getting, if it was just uuid and mobile number then NSUserDefaults would do probably, whereas if you were getting usernames and passwords and other personal data I would looking a mix of keychain and sqlite database.
Also you could use coredata file to store user data but seems a bit over kill as well for for such little data.
Just a little note you are actually not allowed to get the iPhones mobile phone number programmatically, getting this would use Private APIs that Apple would reject your app for using.
2.5 Apps that use non-public APIs will be rejected
So you would have to ask he user for this.
Database selection is totally depend on the architecture and security, if you just need to store the few information like login details and some field then Keychain for login details and plist for data is best option, but if your application also working with services and fetching and saving lots of data and continuously updating it then a serious database structure required. In that scenario core data and sqlite both are good option depends on your preference
Following ways you can save details.
In NSUserDefaults
In coredata file.
In sqlite database
Plist file.(Not recommended)
You can save data at server site using webservice.
Any one of these you can use according to your requirement and data.
Cheers :)
If you store information on the UserDefaults, a jailbroken device can see the information you have stored, it is a plist after all. If you are going to keep sensitive data on your device, user defaults itself is not a good option. Possible alternatives:
Use keychain: Keychain is a tool to keep usernames & passwords securely on a device; so you may need to find a way to convert all the info you have mentioned ( a dict, I presume? ) into NSData and put into/get from the keychain but it's been explained on other threads. Additionally, keep in mind that when the app is deleted, keychain data will persist on the device.
UserDefaults & encrpytion: If you can encrypt the data yourself, than using UserDefaults might be a better option. Its more straightforward than keychain and it will be deleted if you delete the app from the device (which may be the thing you want, or not. It depends)

Resources