I am authenticating using spongeycastle PKCS10CertificationRequest CSR to a RESTful Certificate Authority.
I'm considering using Android Authenticator.
According to: https://stuff.mit.edu/afs/sipb/project/android/docs/training/id-auth/custom_auth.html#Security
It's important to understand that AccountManager is not an encryption
service or a keychain. It stores account credentials just as you pass
them, in plain text. On most devices, this isn't a particular concern,
because it stores them in a database that is only accessible to root.
But on a rooted device, the credentials would be readable by anyone
with adb access to the device.
With this in mind, you shouldn't pass the user's actual password to
AccountManager.addAccountExplicitly(). Instead, you should STORE A
CRYPTOGRAPHICALLY SECURE TOKEN that would be of limited use to an
attacker.
My questions:
I'm not sure what is meant by STORE A CRYPTOGRAPHICALLY SECURE TOKEN in this context.
What does that token look like (its type?) in Android Java?
And where to store it? in the KeyChain??
Is that token used in any other context other than the pw in addAccountExplicitly()?
If your device has rich input capabilities (so user can input username\password) you may want to consider using something like JWT auth. In this case your app never keeps an actual user password, but sends it to the server only once per authentication session and gets back a JWT (JSON web token). This is a token with some information (for example, with a link to user resource - id or uuid) and TTL parameter securely signed with a secret key. This secret key lives on the server only so nobody outside of your server can generate a valid token.
So after authentication request you save JWT localy and use it in the "Authorization" header or as a request field (the first option is better because request body can appears in logs) with every API query. You should renew this token before it expires and if it was expired - then ask user to enter his credentials again. From the server side you get a request, validate a token (is it signed with the server secret key and isn't it expired?) and in case of valid token serve a request. You don't even need to keep tokens on server but you might want to do it if you want more control over authentication - for example, if you want to revoke tokens from outside of application workflow.
There is a list with a lot of libraries for JWT for different languages on the JWT site. For example, for using with Elixir\Phoenix you might want to use Guardian. From Android part in a simple case you don't even need to have a special tools for working with JWT - just put token as a plain text string to the "Authorization" header and send request to the server. But in case you want to get (decode) information your server has put to the token from the app side or check token expiration time - then you'll need to use one of the libraries presented on jwt site.
Related
I was trying to find a way to validate tokens in my Android app, however I read somewhere here that "It's unusual for an Android app to verify or even sign a token." Why is it unusual? Does this mean that there is no way of verifying tokens in native apps?
firstly lets understand what makes a token usable as a stateless auth agent. basically JWT is just a json object which has 3 parts
header
payload
signature
Signature method is sha256(base64(header)+base64(payload)+"secret message").
"secret message" defines how strong the token is. server verifies the validity of the token which this secret key.
Now if you would like to verify the token on your client side, you definitely need this secret key. DOING THIS WILL COMPROMISE THE SECURITY :)
Hope I was able to shed some light on why we should not verify the token on client side. Let's leave the verification to server.
I’m implementing a Android app and that must contain a user login. To do this I create my own authenticator with the purpose of login only once. Then AccountManager can request access tokens, so the application is not handling passwords directly. The AccountManager stores the user account and the token.
I’m using JWT (Json Web Token) to authenticate the user in my REST API.
I wonder whether this flow is correct or there is a better approach to do this in Android.
Here is the flow I am currently using:
The user enter user and passwords in the login screen at first time.
I make a request to server to retrieve a valid token (JWT) that is stored in the Account Manager.
Subsequent requests use the received access token until it is expires (1 hour) to retrieve content from the API.
After the token is expired, it can be refreshed up to two weeks after issue time. From this moment, user credentials are needed to retrieve a new token.
Is this process the correct way to work with the token, and refreshing it? Is the process safe? Are there other options?
Considering this flow is not using a “refresh token” to generate a new one but the access token, what would be the best usage of the Android Account Manager? What other tools should I use? Is it recommended an Oauth2 implementation along JWT in order to implement a “refresh token”?
Cheers!
I can tell, you are on the right road of using JSON Web Tokens and reproducing it.
but the safety you mentioned is all about encrypting the token you retrieved and then saving it in Account Manager (also the same with user credentials) with some encryption method of your choice like AES or RSA and then decrypt if when you wish to use. Also using a server-generated secret key with a secret algorithm would kill the shot for any hacker.
As you understand everyone with a root access can get hands on the saved credentials database and use it.
Using these tricks will lower the need of using Oauth 2.0 which involves a refresh token.
hope it helps
We have a service where user can sign-up. This process is protected by reCAPTCHA to prevent automatized sign-ups. The problem is that on mobile devices reCAPTCHA is not a convenience. Therefore we decided that the sign-up API will accept also some special tokens instead of reCAPTCHA response.
Now the question is how to implement this token. Our first approach was to equip the mobile application with some constant secret that would be sent to the server as the token. But this secret can be revealed if a hacker redirects the request to his server (by updating DNS record of the API domain and installing his certificate as trusted to the mobile device).
Now our final approach is to compute the token as HMAC-SHA1 on username+secret (do we need a here secred - maybe just for making the input long enough?). The username will be taken from sign-up input. Then the server would authorize it by validating the hash. In his case it would be possible to do a replay attack but it is OK because duplicate username would be rejected.
Is this approach correct? Maybe there are other alternatives to captcha on mobile devices?
Also is it possible to get and reverse engineer the application from iOS (ipa file) considering it will be hosted in Appstore and to extract the key (and secret)?
In case of android this is possible - is there a way to prevent it?
You found the disadvantage: you still with a token which doesn't change for the same user. It's ok in your use case (register), but there could be another use cases where is not useful (for example a password recovery feature. In that case, a possible hacker might generate valid tokens for any user is your are asking for the username).
My solution would be:
Create an algorithm (on both mobile app and your backend) that takes a "public token" and creates a "secret token", which solves the captcha. It might be a simple SHA1 hash (I don't recommend), a combination between public token and a salt, the user id and public token, etc...
Create an endpoint on your API that generates public and secret tokens. Store secret token in your backend and return public token to the client (mobile app).
You app then should ask for the public token, generate the secret token and send it to the API. The API verifies that secret token is already stored in your database, and if it's the case then captcha is solved.
An improvement would be making stored secret tokens to expire after X seconds.
Hope it helps!
We decided to go with Hawk to not to send credentials over the wire. It will be used for iOS where it shouldn't be possible to reverse engineer the app and get the secret key. For Android we'll use some reCAPTCHA library for Android.
I see some similar questions related to this question but those ones are too old to be considered, so I will ask again here.
I have an Android App that needs to authenticate to a web service to exchange data that will be stored on Google App Engine. For that, I would like to use OAuth2.0 to provide an authentication mechanism between my App and the web service as shown here: https://developers.google.com/identity/protocols/OAuth2WebServer?hl=en and here https://developers.google.com/identity/protocols/CrossClientAuth
I'm already doing a validation of the token on the web service side as shown on the documentation. The only part that I don't have clear is what to do on the GAE web service and Android after a refresh token is being obtained on Android and validated on the web service.
The questions are:
Must I exchange this token all the time for every communication
between the app and the web service? is it secure?
What is the best way to keep the communications going forward?
After researching about this, this authentication flow I'm using:
Sign in on the app as shown here: https://developers.google.com/identity/sign-in/android/sign-in
After Sign in, obtain a token.
Send the token over HTTPS to backend server
Validate the token on backend server with GoogleIdTokenVerifier verifier (you can also call the tokeninfo endpoint) as shown here: https://developers.google.com/identity/sign-in/android/backend-auth
When you receive the Token on your backend server you should:
After you receive the ID token by HTTPS POST, you must verify the integrity of the token. To verify that the token is valid, ensure that the following criteria are satisfied:
The ID token is a JWT that is properly signed with an appropriate Google public key (available in JWK or PEM format).
The value of aud in the ID token is equal to one of your app's client IDs. This check is necessary to prevent ID tokens issued to a malicious app being used to access data about the same user on your app's backend server.
The value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com.
The expiry time (exp) of the ID token has not passed.
If your authentication request specified a hosted domain, the ID token has a hd claim that matches your Google Apps hosted domain.
User authenticated. Token must be sent over on the request header for every communication with the backend server, then the backend server needs to verify it everytime.
I am trying to secure a Web API which will be used by a mobile app running on Android and iOS. The way it works now is with Basic Authentication with SSL, it sends the username and password with each request to the Web API. I validate the credentials in the Web API in a filter before the action is called. This works great. The problem is, after users login I have to store the password on the device (Android/iOS) to save the session or they will have to login all the time. This isn't secure because if the device is hacked the credentials can be accessed. I'm looking for a way to user basic authentication without storing passwords on the device.
I think the solution in this article can work but I am unclear how to make it work. In the accepted answer it says
Generate a key for each of your apps and have them pass the key in each request as a token. Your server can then verify the key and authenticate the request.
Take a look at the Basic Authentication module from the ASP.NET site. The sample uses 'basic' as the authorization scheme but you can change it use 'token' instead.
I am not clear exactly on the process here. In this example there doesn't seem to be any username/password involved even during initial login. How would the user obtain the key without logging in? Then, what exactly is the "key" referred to in the quote. That could be anything such as a Guid? I am also not understanding how this is anymore secure than storing a username and password on the device if is hacked. The hacker could use the "key" just as the username and password correct?
that's basics of authentication, I'll explain the process in a simplfied way. Hope you understand.
user types name and password and tap login.
device send name and password to server.
server authenticate and respond with a long random unique sequence of characters (a.k.a. the key).
Both device and server stores the key.
All other requests uses the key to authenticate.
For every call, the server checks if the key matches the one it have stored.
device never stores the username or password.
server can disable/delete that key if suspect of breach, in which case user will have to login again
Do all of this using encryption. Everything!