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
Related
I plan to develop a command line client for a web API protected by OAuth 2 (JWT). The access and refresh tokens live for five and thirty minutes, respectively. Since the user will use the command line client for longer than five minutes in a sitting (a testing or debugging session, for example), the refresh token needs to be stored on the local computer, so that only one authentication is needed at the beginning of the session, and not later on.
I wonder where I can store the refresh token securely. A text file in the user's home directory might not sound too bad, because that's also the place the user stores all his or her private documents. However, any other application run by the same user could read that token and misuse it.
What are common solutions to such a problem?
Here you can use Resource Owner Password Credentials Grant in which you will use command prompt to get end user credentials and exchange them for tokens. With that, you can think of a way to encrypt received tokens based on end user credentials you got when requesting tokens. So whenever you require to use refresh token, you can prompt end user for their password so that you do not store the password but also you encrypt tokens so no other process can steal them as it is.
Use ROPG as Kavindu says - if you have an implementation that supports refresh tokens
After that you can store tokens in memory or via OS secure storage. The choice is a little subjective and depends on sensitivity of data being accessed
If using OS secure storage then store tokens per app + user, to ensure isolation
An example cross platform component that does this is keytar, which I've used in the past for desktop apps - it is nodejs based -not sure if this works for you:
https://github.com/atom/node-keytar/blob/master/README.md
Sample code that uses it
See the OS Secure Storage section of this write up to understand how the entry can be viewed + managed via built in OS tools:
https://authguidance.com/2018/01/26/final-desktop-sample-overview/
Currently, I am getting an API key from the server after logging in and using it to make http requests. I currently store the API key in the iPhone app's database. However, I've heard that I should store it in a keychain from a colleague. So, I searched on Stackoverflow and seen questions regarding this. It seems this isn't really a secure way of storing API keys at all.
Secure keys in iOS App scenario, is it safe?
In iOS, how can I store a secret "key" that will allow me to communicate with my server?
I don't know a way to stop hackers from reverse engineering to get the API key from the iOS app. A user on StackOverflow basically said it will only overcomplicate things for little to no benefits.
I need to find the post, but someone recommended to just make sure you're making a secure API request (SSL certificate) and you have a way to remove the API key if someone is hacked.
As already pointed out by #jake you should use a token tied up only to the user instead of an Api Key for all users, but other enhancements can be done for further protect your App when doing the http requests.
The user token can be a signed JWT token and then you can enhance the security of the communication between your server and the App with Certificate Pinning in order to protect against Man in the Middle Attacks.
Other techniques like the use of OAUTH2 and hiding secrets can be used to enhance the security of your App and you can read more about it here.
Keep in mind that Certificate Pinning can be bypassed by hooking frameworks such as Xposed that contain modules specific to bypass the pinning, but still another layer of security that you should not discard once it will increase the effort necessary to hack your App on the device and will protect your App against Man in the Middle Attacks.
For ultimately security between your App and the back-end you should use an App integrity attestation service, that will guarantee at run-time that your App was not tampered or is not running in a rooted device by using an SDK integrated in you App and a service running in the cloud.
On successful attestation of the App integrity a JWT token is issued and signed with a secret that only the back-end of your App and the attestation service in the cloud are aware and on failure the JWT is signed with a fake secret that the App back-end does not know, allowing this way for the App back-end to only serve requests when it can verify the signature in the JWT token and refuse them when it fails the verification.
Once the secret used by the cloud attestation service is not known by the App it is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.
You can find such a service in Approov that have SDKs for several platforms, including IOS. The integration will also need a small check in the App back-end code to verify the JWT token in order the back-end can protect itself against fraudulent use.
JWT Token
Token Based Authentication
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
Certificate Pinning
Pinning is the process of associating a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a pinset (taking from Jon Larimer and Kenny Root Google I/O talk). In this case, the advertised identity must match one of the elements in the pinset.
OAUTH2
The OAuth 2.0 authorization framework enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf. This
specification replaces and obsoletes the OAuth 1.0 protocol described
in RFC 5849.
Disclaimer: I work at Approov.
A more secure mechanism would be to return an authentication token on login. This authentication token should be unique to the user. If you have proper authorization and security mechanisms on the backend (to mitigate DDOS attacks, injection attacks, users accessing other user’s data, etc) then who cares if they get their authorization token from the keychain or wherever it is stored? Since the authentication token is tied to their account you could just invalidate the token so it stops working if the user is malicious. And you could even disable their account altogether if you have the right mechanisms in place on the backend.
Many of the security mechanisms can be automated on the backend. Platforms like AWS can easily be configured to automatically disable accounts that are doing certain malicious calls to your backend.
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.
There appears to be four distinct flows in OAuth2, i.e. (link),
Authorization Code Flow - used with server-side Applications
Implicit - used with Mobile Apps or Web Applications (applications
that run on the user's device)
Resource Owner Password Credentials - used with trusted applications
such as those owned by the service itself.
Client Credentials - used with Applications API access.
If I'm developing a mobile application that will consume resources from its own API, i.e., the mobile app is developed by the same team developing the API, which of the four OAuth flows should I use and how?
Given my scenario, it sounds to me like option 3 is the way to go. If this is the case, would you adopt the following process:
Release you mobile app with the ClientId and ClientSecret stored on
it (deemed okay as the application is trusted).
Ask the user to log into their account using cookie-based
authentication (immediately deleting their username and password).
Cache the hash of their username and password returned in the
response of the cookie-based authentication.
Use the cached username and password, along with the ClientId and
ClientSecret, to request access and refresh tokens from the token
endpoint of the OAuth server.
Doe this seem sensible? It would be good to know if I'm on the right track with the above thought process, or if I'm going something incredibly silly and ought to be doing this some other way.
Resource Owner Password Credentials flow would be okay for your case.
BTW, it is difficult for a mobile application to keep its client secret confidential (RFC 6749, 2.1. Client Types, RFC 6749, 9. Native Applications). Therefore, in normal cases, a client secret should not be embedded in a mobile application. In other words, embedding a client secret is almost meaningless in terms of security.
2- Implicit - used with Mobile Apps or Web Applications (applications
that run on the user's device)
If your application runs entirely on a mobile device then you are encouraged to use this flow as your mobile app can't be trusted to keep its client credentials secret.
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.