Setting credentials in code can still be compromised even after keychain security - ios

I would like to store username, password, auth token in my iOS app so that I can connect to my db, perform operations etc. I notice that the recommended way is keychains. The reason for this is that a malicious hacker if got your ipa by jailbreaking or something else can read your code and look at the username/password.
But my question is once the user logs in and I save their username and password in keychain, I set the credentials in the code itself so how is this secure? If a hacker gets an ipa and opens up the code, they will see where I'm setting the password anyway or if there a place to store this so no one can really see it.
I have been reading a lot about how secure keychain is and I definitely agree it is, but setting the value in keychain has to be done in the code itself which worries me if someone gets the code and can see it.
Reference: https://medium.com/ios-os-x-development/securing-user-data-with-keychain-for-ios-e720e0f9a8e2

You can add an extra layer of protection by detecting if App is running on a jailBroken phone
How do I detect that an iOS app is running on a jailbroken phone?
Also keychain provides protection to passwords or private keys as the data is encrypted.
An application can access only its own keychain items, or those shared with a group to which the app belongs.
https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html

Related

Should I save passwords in shared web credentials AND (local) keychain

I am in the process to design a login for a new app that will be associated with a domain, i.e. be the counterpart to an SPA.
Obviously I want to use
iOS 11 Password Autofill, and
Shared Web Credentials
I have read the documentation on autofill as well as watched the WWDC video about it. Also, I checked the article on Shared Web credentials, which I think is older than the new, reworked autofill. Said article recommends:
Do not use the shared web credentials as your primary storage for secure user credentials. Instead, save the user’s credentials in the keychain, and only use the shared web credentials when you can’t find the login credentials in the keychain.
This strikes me a little odd, because it
- Means I have to cover more possible inconsistencies, i.e. synchronize the keychain somehow wit the shared web credentials (what if I have credentials in the keychain as well as the shared web credentials, but they're different?)
- Potentially leaves "garbage" behind in the keychain if my user user uninstalls my app (naturally I hope they won't ever do this, but let's be realistic, some will)
Especially the last point had always bothered me in the past (before shared web credentials and autofill were a thing, or when my app doesn't have an associated domain). Unlike on macOS, the iOS Accounts & Passwords feature (in the Settings app) doesn't list ALL passwords, but only the ones used by Safari (i.e. the shared web credentials), correct? Keychain Access on macOS instead offers a means to view and manage all credentials, even those that aren't synchronized over iCloud.
I understand why the same is not offered on iOS, but it also means that for those passwords that my app saves (locally) to "its" keychain "part" can only be managed if I offer a UI for this in my app. And if the user uninstalls the app before using this, the item will stay in the keychain, at least it was that way when I tried it a couple of years ago.
My main question now is, wouldn't it be easier to disregard the article's advice and only rely on the shared web credentials for password storage? That's the part they can edit in Settings (if ever need be) and also it will reflect any password changes done on the website. I would design my app like this then:
First launch: App starts on the Login screen and offers the username/password via Autofill
User logs in: App saves a simple flag in the shared user defaults indicating the user is logged in.
App gets relaunched, e.g. after a device reboot: The app skips the login screen due to the flag and gets the password and user name from the shared web credentials (assuming the user previously granted it permission, of course)
User explicitly logs out: The app deletes the flag, basically setting everything back to first launch
User deletes the username and password from the shared web credentials (e.g. in the Settings app or with Keychain Access on macOS): The app falls back to the login screen as soon as it detects this (e.g. when attempting a remote request, or after relaunch), regardless of the flag. I think this matches the user intention best (if you delete a password you don't want some apps to hold onto it until you log them out)
This setup would avoid any issues with different items in the keychain and shared web storage and it would immediately propagate updates done in the webpage to the app as well (which is what I'd intent for my app anyways). Is there anything that would keep this app flow from working?
(Note: I asked the same question on the apple developer forums, so if you see that as well don't be confused. I will update any potential answers from there to here and vice versa.)
Edit to address #Aaron's answer:
Thank you so much for the info. Your answer helped me realize I misunderstood something about shared web credentials: I assumed that for an app with associated domain, you can access the credentials without user interaction (after perhaps an initial authorization). Like you can set the checkbox on macOS when an application requests credentials. I now realize this is wrong and on iOS you would always have to verify with the user, thanks.
For completeness sake, I still want to point out some of the other things you said:
You are right, we will eventually use token based authentication, so I will save that in the keychain (probably in addition to the password, see below). I just tried to keep the question simple enough at first.
Our app is like an email client where you update new incoming "mail". The mentioned "login flag" in something like the user defaults would thus just indicate whether the app should behave as if subscribed to an inbox or not. Like in Mail, you wouldn't expect to have to login even after relaunch.
For this reason I will probably eventually save the user's password in the (local) keychain along with a token. If the token expires, I can request a new one without user interaction, that's important in our general site and app design. Only if that request fails I would use the shared web credentials (updating my local copy of the creds in the process).
For what it's worth, the last point you mentioned is probably debatable. On macOS, for example (where you can edit the entire keychain, not just Safari passwords) de facto logs you out of an app. Mail, again, as an example. If the keychain item for an inbox is gone, Mail re-asks that the next time it is launched and tries to access the content (effectively a "kind of" login in a way).
Again, thank you a lot for answering, now I can close an open todo. :) Also thanks to #HamZa for giving out a bounty!
Considering this advice:
Do not use the shared web credentials as your primary storage for secure user credentials. Instead, save the user’s credentials in the keychain, and only use the shared web credentials when you can’t find the login credentials in the keychain.
The main issue here is that the shared web credentials process is a little clunky — it requires user interaction and takes time to resolve the credentials. So if the user has already authenticated with your app you want to avoid showing them the login page at all. You can do this by storing credentials in your app's keychain where you can access them immediately without a network connection or user permission.
This doesn't mean you need to store the user's password in the keychain. Typically you would store something like an OAuth access token in the keychain. The presence of this token means the user is authenticated - and if an API endpoint rejects your token then you can take them back to the login page.
This suggestion:
User logs in: App saves a simple flag in the shared user defaults indicating the user is logged in.
is possibly insecure depending on what you're hiding behind the login page, but typically any content belonging to the user should require a valid token to access, not just a bool in the user defaults.
I think this matches the user intention best (if you delete a password you don't want some apps to hold onto it until you log them out)
I disagree with this; I would not expect an iOS app to log out because I deleted a password from my Safari keychain.

Storing password in the client side using Appcelerator - Design Approach

I am creating an application using Appcelerator wherein the user needs to enter the username and password to login. Once logged in, the user can enable TouchID for authentication. After logging out, the user can use the TouchID for authentication and use the application.
My flow is that once the username and password is provided, I store those two information in Keychain using the following module iOS Keychain Module. Then I use ti.touchid to authenticate the fingerprint, if success, then I retrieve the username and password from keychain and then send it over HTTPS web service call and login the user to the application.
My query is that, whether this is an acceptable approach.
I am not an iOS developer nor does any ti or keychain terms mean anything to me at all. That's for a start and to reduce the number of down votes i might get.
In terns of security, I would suggest that you imagine obtaining that particular user's phone where you know you have some authentication credentials stored. Let's say I am a user of your app, already logged-in and have my credentials saved somewhere on my device, and you obtain this phone by stealing it from me.
Now, will you be able to access my account in anyway? Will a hacker with access to the physical phone be able to retrieve any information stored in your Keychain storage?
If so, If you can think of anyway to do so, then your approach is not valid.
I understand you want to save users sometime by making sure they can login with just their fingerprint, which is a valid reason to think of such an approach, but you will have to think everything in terms of reverse engineering.
Additional recommendations would be using an on-the-fly hash to store information in the Keychain and making sure to check that before restoring the same. For example, user credentials saved on "home wifi" can be verified with your fingerprint only "at home" on the same wifi network where the same will be invalid on a different network.
i.e)
(keychainItem.x = y) is TRUE ONLY IF (something else)
where this (something else) is something that will prevent hackers from accessing the Keychain even if they have access to the device itself.
I do this myself when programming web applications with stored cookies. I for example use a stored cookie ONLY IF it is being accessed from the same IP it was saved from. Anytime that IP address changes, user will have to re-authenticate even if the cookie values are correct.
Hope this helps.

Using Touch ID on iOS to encrypt data

What I'm trying to do
Basically what I'm trying to do is figure out a way to encrypt data using Touch ID.
Sadly I've not found a way to create an encryptionKey with Touch ID, since the LAContext API only returns a aye/nay response.
Why I'm trying it
I'm implementing different log in methods in an app. The supported log in methods are a password, PIN-code and Touch ID. The user is free to choose whatever log in method he/she wants.
Only the password however, is send to the server which will authenticate the user. As such, only the password is stored in the keychain.
The encryptionKey, used to first encrypt and then store the password in the keychain, is created using whatever method the user chose as log in method.
If the user chose to use a PIN-code, the encryptionKey is derived from that PIN-code, the same can be said when the user chose a password as log in method.
My question is:
How can I fit Touch ID in this picture?
I've searched on the internet, but only found what I already feared.
Since iOS only returns a true or false from the Secure Enclave, it's impossible to create an encryptionKey.
I know the keychain is encrypted by itself, but for security reasons (please don't elaborate on this) I need an encrypted password stored in the keychain.
EDIT:
The reason behind storing data encrypted in the keychain is because the keychain can be breached by jailbreaking a device.
And since the app I'm working on allows users to view (mostly) corporate sensitive data, I need to take even jailbreaking into consideration.
Use the kSecAccessControlTouchIDCurrentSet or kSecAccessControlTouchIDAny keychain access control attributes to protect your encryption key in the keychain. Using this API will fail if the user does not have Touch ID enabled (or the device does not support it), and using kSecAccessControlTouchIDCurrentSet will fail if the user modifies the set of fingerprints. In case of failure, you can then fallback to your normal authentication UI, such as pin code or password entry.
See the WWDC 2014 711 Keychain and Authentication with Touch ID talk and WWDC 2015 706 Security and Your Apps for more information.
As a general note, do not store data in the keychain. You should only store passwords, encryption keys or credentials, and use those to decrypt data stored on the disk.
I know, this question was posted back in 2015, but I researched for the same problem. As Far I know, it's actually not possible.
I have found this Quote on the 1Password website concerning this topic:
Don’t jailbreak your device. Someone with physical access to your device could theoretically access the secret that 1Password stored in the iOS Keychain. However, that would require unlocking the device, jailbreaking the device (so that something other than 1Password can read the iOS Keychain data that belongs to 1Password), and defeating the obfuscation of the Master Password. If you jailbreak your device, you are willingly defeating one of the strongest defenses against such an attack.
So, simple answer: It's not possible :(

IOS Keychain Service

I'm new to iOS development and programming, so please bear with me.
Correct me if I'm wrong but, conceptually, an app can access any items in the Keychain that are associated with the app. It is my understanding that hackers can manipulate the code of an application like "Jailbreaking" to do the hacker's bidding.
In that case, is it possible for the hacker to simply access all the elements of the Keychain by adding additional code?
For example, if my app is checking authorization by comparing the inputted value with the Keychain stored password, could the hacker simply modify the code to get the Keychain stored password? If so, how do you guard against this?
Yes. Anyway, you should be storing the password hash, not the password.
You cannot protect the user against themselves. It's their data. You can't keep them from reading their own data.
The alternative is to store data on your server instead of on the device.

Storing authentication tokens on iOS - NSUserDefaults vs Keychain?

Which is the place I should be storing tokens for when the user logins in to a service? I'm not saving passwords (obviously where I'd use the Keychain) but just the token. A lot of places say just use NSUserDefaults but some people on StackOverflow seem really keen on the Keychain.
Is NSUserDefaults fine?
I would highly recommend you use the keychain - it's exactly what Facebook do for storing their session tokens.
NSUserDefaults is not secure or encrypted - it can be easily opened and read, both on device and when synced to a Mac. So whilst user defaults is a good place for things like preferences and config info, it's not a good place for anything sensitive, like passwords.
Session tokens should almost always treated the same as passwords, so you should store them securely in the keychain, where they'll be encrypted. Apple have some sample code (GenericKeychain) that shows a basic implementation, and you'll find other examples by searching StackOverflow. Hope that's helped you out.
NSUserDefaults can be used without any problems (for tokens!).
Please check documentation https://developer.apple.com/documentation/security/keychain_services
Keychain Services are invented to “secrets” that the user explicitly cares about, i.e. passwords, private keys or even secure notes, i.e. clear credentials. But access tokens are temporary hashes generated after user entered password and have limited time. And even if stolen, the malefactor cannot completely stole the account - the owner can login on another device and previous access token will be reset. So, formally there is no forbiddance to store access tokens in UserDefaults.
The data from UserDefaults can be stolen only if the device is stolen itself, but I think the security level of the content is much lower than the physical device itself. I think user would not worry about the token in that case, but about the device.
However, it’s a good practice to store it in Keychain, but it’s just an excessive (!) usage of security and usually recommended by random users in the Internet and it’s not required by Apple. There is no documentation by Apple there they say that tokens must be stored in Keychain (if you can find one, then please comment one below).
So, the answer is - you can use both. However, if you app is operating with content that costs a lot in contrast to stolen iPhone, then it's better to use Keychain, but it's just a recommendation.
All sensitive data should be stored in the keychain.
UserDefaults is for small pieces of data like user preferences.

Resources