Should access tokens for services like Twitter and Facebook be encrypted?
In particular, should tokens be stored on the the device's Keychain vs. UserDefaults? What are some possible security issues that could arise if a user's device is stolen/taken
This is what I have come up with so far.
Pros of Keychain:
Encrypted
Cons:
No way to clean up when user removed app
Pros of UserDefaults:
Kept inside the app.
Cons:
No encryption.
Your UserDefaults 'con' needs amending: no encryption by default. You can encrypt the content yourself using e.g. CommonCrypto, but it needs additional work over storing the plain text.
The point of an OAuth token is that someone who owns that token can use the relevant service without having to present credentials. Therefore, you should protect it like you would protect the password if you had to store that instead, as it has the same value.
If the user's device is stolen, then unless they have passcode-locked their device the thief has the capability to use your app as the user in either of the situations you describe. If you do not encrypt the access token, then they additionally have the capability to extract that and replay it from code under their control.
Related
I always wondered how native applications like the Dropbox client or any other native application with a serverside service implement the "keep logged in" feature securely.
Do they store the users credentials? Or do the store a never expiring access-token?
How are the credentials / access-token stored? They must be encrypted in any way.
When encrypting the data, how is the key generated? A fix key wouln´t make much sence because the code could be reverse engineered.
Is there a best practice or industry standard for storing credentials / access-tokens securely?
Native apps can use built in secure storage to store OAuth tokens after login:
Tokens are encrypted with a key that is private to the app and user
They are stored in Operating System Secure Storage, eg Windows Credential Manager / MacOS or iOS Key Chain
The refresh token can have a long lived expiry but it is not infinite
Standard libraries usually do the lower level encryption work
The key benefit of course is that the user does not need to log in on every app restart. As an example:
A desktop app of mine deals with OS secure storage via this code.
And the end of this blog post shows the stored credentials.
The same principles apply to mobile:
iOS
Android
I want to implement a second security, because when the phone is jail broken the keychain is vulnerable and I don’t want my passwords to be secure only by the keychain. That’s why I want to encrypt the password by me before save the in the keychain.
The reason I want to encrypt it is because the server for login accepts a plain text password not hashed. I had the idea to have a rout for encrypting and when the user logins for first time, the password is send as a plain text and after that encrypted.
The encryption to happens on the backend and the backend can decrypt it. Is this a good idea, because when the user changes his/her password he/she needs to enter the old one as a plain text and I call the encryption rout on which I sends the password. It is responding me with an encrypted one of it and I am
comparing them. So in the keychain is only the encrypted one.
Is there a better way if it is where to store the key if I am encrypting the password on the device? If it is a static hard-coded field it is not OK. If it is in the keychain too, and on the server it is possible to have a different encryption key for every user. What is the best way to do it?
There is no good answer to this question, as the threat vector is too broad. You want to protect some secret information even if the device security is compromised (someone other that the user of the phone has jailbroken / hacked it). The best information about this can be found in the article Secret Management on iOS.
TL;DR: “Don’t (but if you must, obfuscation wouldn’t hurt).”
Is there any way that a third-party app can logically use Touch ID to authenticate to a web service that uses OAuth2?
Say I own a web service that requires authentication using OAuth2. It supports both the implicit and authorization-code grants (although I could add support for other grants if necessary).
A third party has a mobile app that uses this web service. It opens a native web view to authenticate, and loads my auth URL in it. The user enters their username/password on my domain, and I return an OAuth token back to the app.
If this app wants to implement Touch ID to speed up authentication, is there a way to do it that makes sense with OAuth2?
My understanding is that the purpose of the OAuth2 implicit and auth-code grants is to prevent the parent app from having access to the user's credentials. It only gets access to the resulting OAuth token, and that's only valid for a limited time.
With Touch ID, you would typically store the password using Keychain Services. So this obviously requires you to have access to the password.
I suppose they could store the OAuth token in the keychain instead of the password, but then this would only be valid for a short time.
The only answer I've come up with so far is what you allude to at the end: store the OAuth tokens -- but also a long-lived refresh token. How long that refresh token can live is definitely dependent on your specific security needs.
I don't know about any standard flow yet but here are some common considerations. Simply storing long-term credentials (passwords or refresh tokens, even encrypted at rest) would be mixing up security contexts in a way that is hard to audit. When using any local authentication (app-specific unlock PIN, any biometrics, or simply system unlock) it's important to do it in a way that can be verified by the server. So the first step would be device authentication, every instance of your app should use unique client id/client credentials (I suggest to implement Dynamic Client Registration Protocol to help with that but there could be other options). Then, it's a good idea to generate some piece of verifiable key information directly on the device, put it into secure storage (protected by whatever local unlocking mechanism and invalidated whenever biometrics changes or) and use it to generate a MAC of some kind, for example a JWT as a part of jwt-bearer flow (or some new extension to OAuth assertion framework). JWT tokens could include additional metadata (claims) that can provide more context to the server, like it can make informed decisions to force re-authentication in some cases.
To restate:
Device is authorized and issued an unique client credentials pair.
Locally-generated key is saved to the encrypted storage and protected by some local unlock mechanism (system lockscreen, PIN, biometrics, etc.)
The key gets registered with the server and tied to the device.
On unlocking the key is used to generate a JWT that is used as assertion for authenticating with the server.
Seems pretty standard to me, maybe someone should write up a BCP for this after thinking through all the implementation details, current practice, and security considerations.
At the moment I'm storing both the username and password for communication with the server (through Alamofire) in the iOS keychain. However, every now and then the keychain returns nil when trying to retrieve these items. Therefore, storing the username and password in the keychain is not a reliable option. Is there a better way to communicate with the server? Maybe a session cookie or something?
Do you have freedom to modify the server-side code? If so, you could check out JSON Web Tokens: https://jwt.io/
If not, instead of the keychain we could use NSUserDefaults (https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/). But remember that this is an interface to store user preferences, it is insecure to store passwords in it. That's why you should consider using tokens.
See this related question: NSUserDefaults or keychain is better to save username and password in iPhone app
I am planning to make a ASP.NET Wep API server and a IOS client.
From what i have read, the KeyChain is the only place to store IOS sensitive data such as passwords.
Considering a RESTful stateless service: the username and password must be sent to the service with each request.
This stateless service seems to bring the following two extra operations with each call:
Go go KeyChain and get credentials
Validate the credentials
Q1:Does that mean that for every request password must be retrieved from the KeyChain and passed to the server?
Q2: That makes me wonder, go stateless or not?
The keychain is the place to persistently store sensitive information, yes.
If you are using a username and password and keep it for the duration, storing it in memory (RAM) is typically ok. If you wish to remember it for next time so the user must never provide it again, you must store it in the keychain.
Typically you store the password in memory (even for a session) once retrieved from keychain.