RESTful stateless service and KeyChain. Go stateless or nor? - ios

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.

Related

OAuth2 app with Touch ID

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.

How to communicate with a server that needs authentication?

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

OAuth2 refresh token in cookie

We are creating an Asp.NET MVC-5 application with Identity, and the database is accessed through a WebAPI using OAuth2. When a user logs in with a username and password, the MVC application uses this info to log in to the WebAPI to request the first access_token and refresh_token. These tokens are stored in the MVC application in a dictionary with the user's username as the key. The tokens are not exposed outside of the MVC Application. We then use the user's username to retrieve the tokens from the dictionary each request that the user makes.
We use Identity with Cookie Authentication in the MVC Application. The MVC Application is going to restart every once in a while (every week or so), which means we'll lose the access and refresh tokens stored in memory.
My questions:
We use the UserName provided by User.Identity.Name as the key to retrieve the user's access_token and refresh_token from the dictionary. Is this safe? I assume Identity retrieves this from the cookie. Would it be possible for a user to change the cookie to pretend to be another user, or is Identity's serialization safe enough?
I plan to store the refresh token in the cookie as well, so that when the MVC application has restarted, we can use this token to authenticate the user without forcing the user to log back in. This is basically the same question as 1. Is this safe?
If both are in fact not safe, would it be sufficient to create a small local database where we store this data, and use a GUID in the cookie to retrieve it? We're trying to avoid needing a local database, but if it's necessary then so be it.
Thanks for the help.
It's not secure to store the refresh or access tokens in cookies.
Please refer to Where to store access and refresh tokens on ASP.NET client web app - calling a REST API
You shouldn't be concerned about "losing the access and refresh tokens stored in memory". If it happens, just recreate them.
BTW: Storing any user data at in-memory dictionary is not a good idea. Use ASP Session management. It would be much easier to add any backed to that (in-proc, database, redis).

Verifying a user when backing up data to a server

Note: Although I raise this issue in the context of an iOS app, I don't think it's confined to an app running on that specific OS.
I'm developing an iOS application that will back up user data to a server and I'm trying to figure out the best way to verify server-side that the user being updated is actually the real user. Each user will have an id (uid). If that's all I depended on server-side, then I imagine the process would go like this:
User runs app for the first time
Creates account in the app, which communicates with the server to both create the account on the server and to get a unique "user id" (uid)
App stores this uid so that it can identify the user in subsequent communications with the server
However, if someone were to hack the app on their iphone, they could change the user id value and then that would instantly give them access to/allow them to modify a different user's data.
The current solution I'm considering is that the user receives 2 unique ids, the uid (just an auto-incremented number) and a longer, more complex key string. All communication with the server will therefore have to send along both the uid and the key. The server will verify that they match in order to make sure that the user truly is who the app says it is.
So, my question is two-fold:
Is this the correct way to achieve this? Or is there some other standard method that I should pursue?
If this is the correct approach, what's the recommended way to generate the unique key?
First of all, you can use the more complex value as the user ID to begin with, if you like (e.g. a UUID). Monotonically increasing IDs get hard to manage as your service scales.
You have the same problem a secure web site does when it leaves secure cookies on the browser to remember a session. Those cookies do include the user ID, but must prevent tampering. This is generally done by signing the cookie on the server before sending it back.
So what you'd do is:
Generate the user ID on the server, and use it to create some sort of "auth token" for the client to have to sign in.
Sign the auth token on the server with a secret key that only your server knows.
Send the auth token to the client, where it is stored for all subsequent logins. Transfer the auth token over HTTPS to prevent someone else from snooping it on the network.
When the app goes to login, send up the auth token to the server. If it's been hacked, the signature validation will fail, and you'll know to reject the client.
Consider including a timestamp in the signed token as well, so it expires after some time, forcing the server to regenerate an auth token periodically, which protects you in case your key is compromised. It's hard to do this all fully unless the user himself has a shared secret/password he can use to authenticate periodically as well. Depends on how far you need to go.
Other considerations: If all you know about a user is their generated UID, you don't have any way for that user to come back later from a different iOS device and restore their account there, right? Generally, if the user will be creating anything "valuable" in their account that they'll want access to later, you'll probably want to create a more traditional user account backed by an email address and password or the like, so they can access the account again after reinstalling your app. (This may or may not be relevant to your case.)
I would recommend going the "standard web browser way" and just letting the user set an email (login) and password.
When the iOS device connects to the server (using HTTPS), it uses regular "basic authentication" to log in, and receives a cookie which is valid for a set period of time. As long as the device keeps requesting data from the server within the cookie's lifetime, the cookie is renewed, and when the cookie is expired the server will automatically challenge the client to log in using its stored information again.
This has some advantages;
The user can log back into his account with a new device with a regular password reset. Easy, straight forward solved problem.
There is no special solution on the server side, any server side script can require authentication just like it would for a browser - built in functionality.
You would not have to invent your own security scheme. This scheme is used by millions of browsers every day to authenticate to web sites.
Not tied to a special phone, if the user has several iOS devices, he can use the same account from all of them by just logging in. No special set up procedures.
In other words; no special solutions for you to develop, generally solved problems how to handle login information, proven security and ease of use.
According to me, you can't really beat that :)

Access Tokens Persistence Best Practices (iOS)

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.

Resources