Captcha substitution on mobile devices - android

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.

Related

Android Authenticator STORE A CRYPTOGRAPHICALLY SECURE TOKEN

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.

User Authentification on Android - Security Implementation

I've been mostly creating smaller apps and games for Android so far, but am now creating a somewhat big app with lots of users and more sensible data than a highscore.
My normal approach was to just have a table for all users with passwords, authenticate with a simple Login Screen using a HTTP(S) call and that's it.
There's a few things I want to improve for this app though:
Secure Transmission
If I want to encrypt the user's password, where do I need to do it? On the device, before it's even sent? (In case of unsecure networks, like a public WiFi hotspot) Or better on the server, before writing it into the DB? Or should I just use SQL's encryption?
Auto Login
I want users to be able to stay logged in until the log out - how would I best do that? Not just security-wise, but also for the user experience.
My research shows me that using the AccountManager would be best to save the username and password and authenticate automatically when the app is started. Is there anything more to it, any security risks I'm missing here?
Access control
Usually, I would just expect every call made by an app to be valid, since a user can't access anything but the login screen without logging in. But how do I best authenticate a user's request to make sure that it's not an attacker? I can't just send the username/id with every request, so I probably need like a session token that I generate on each login? Or is there a better method?
Is there anything else I've forgot to think about?
I would suggest you to transfer password without encrypting it but by https. Other way would be to implement asymmetric encryption in your app and encrypt password with public key which you will receive from server.
On the server side I would hash password using some hashing algorithm with salt. And store only hash and salt. When users will log in, you can hash incoming passwords the same way and check hashes on equality.
To make auto login, you need to sign all requests from authorized users with a token. Token you will receive from the server after successful login. This token could be stored in Keystore, or special storage which is accessible only for this application.
Signing could be implemented by attaching to request additional parameter with checksum from all request parameters and token.
Additionally I would suggest you to think about unauthorized clone apps, which could pretend to be your app and call your server side API.

How to secure Web API for android/ios apps with basic authentication

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!

What is the preferred way of using AWS (specifically S3) from mobile apps?

Adding the AWS access key and secret key directly in app code is definitely not a good approach, primarily because the app resides on the users device (unlike server side code), and can be reverse engineered to get the credentials, which can then be misused.
Though I find this information everywhere, but am unable to find a definitive solution to this problem. What are my options? I read about the token vending machine architecture for temporary credentials, but I am not convinced that it is any better. If I can reverse engineer the secret key, then I can reverse engineer the code which requests for temporary credentials. And once I have a set of temporary credentials to access S3, I am as good as if I had the key. I can request the temporary credentials again and again, even if they expire pretty quickly. To summarize, if an app can do something, I can do the same as a malicious user. If anything, the TVM can be a bit better at management (rotating credentials, and changing key in case of breach, etc.). Please note we can put the same access restrictions on the secret key, as we plan to do in case of TVM temporary credentials.
Additionally, if Amazon doesn't want people to use the secret key directly in the App, why don't they block it in their SDK, and enforce TVM or the correct solution. If you will leave a path, people are going to use it. I read several articles like these, and wonder why?: http://blog.rajbala.com/post/81038397871/amazon-is-downloading-apps-from-google-play-and
I am primarily from web background, so my understanding of this may be a bit flawed. Please help me understand if this is better, and whether there is a perfect (or may be good) solution available to this problem.
PS: Is there a rails implementation of TVM?
Embedding S3 keys in App code is very risky. Anyone can easily get that key from your app code (no reverse engineering or high skill set required), even if that is stored encrypted it is still compromised just that someone need to try harder (depending on how do you encrypt).
I hope that you understand the advantages of using temporary credentials to access Amazon (S3 etc) resources (mainly security + some others like no app update etc). I think you are more confused about the process to get the temporary credentials from TVM and how that is safer than embedding keys in code.
Every client using TVM first need to register with the TVM server implementation hosted by you. The communication between App (using TVM client) and TVM server is over SSL.
First the app register with TVM by providing UUID and a secret key. Please note that the secret key is not embedded in App code (which I think is main reason for your confusion) but generated randomly (using SecRandomCopyBytes which generates an array of cryptographically secure random bytes) at the time of registration (and hex encoded).
Once the device is registered successfully with TVM, the client TVM store the generated UDID and secret key in a storage called Keychain in iOS and Shared Preferences in Android. The keychain in iOS is the shared storage provided by iOS to securely (encrypted) store information (mainly keys, password etc).
After registration and UDID/Secret Key storage, App can get the token from TVM by sending the UDID, cryptographic signature, and a timestamp. The cryptographic signature is an HMAC hash generated from the timestamp using the secret key. The TVM can use the UDID to lookup the secret key and uses it to verify the signature. The TVM then responds by sending back temporary credentials, which are encrypted using the secret key (uses AES). The application decrypts the temporary credentials using the key and can then use them to access any AWS services for which the temporary credentials are authorized. Eventually, the expiration time of these temporary credentials will be reached, at which point the application can get the fresh temporary credentials, if required.
I am not sure how signed URLs relate to TVM, because I don't understand the concepts 100% but signed URLs really solved the problem for me. I needed a mechanism that would feed web app and mobile app data without allowing for misuse of the credentials. Putting the key in the code is indeed a very bad idea as it may generate a huge bill for the company.
After 3 days of extensive research, I found a simple and, what seems to be, a reliable and relatively safe solution: signed URLs. The idea is, that a very light-weight back-end can generate a temporary URL that will grant the user access to the specific resource for a limited time. So the idea is simple:
the user asks our back-end with a Rest call that he wants a specific resource
the back-end is already authorized with AWS S3
the back-end generates a temporary URL for the user and sends it in the Rest response
the user uses the URL to fetch the data directly from the AWS
A plug-and-play Python implementation can be found here and with a slight modification that I had to use: here.
Of course one more thing to figure out would be how do we authorize the user before we know that we can grant it the URL but that's another pair of shoes.
You should ideally use Cognito Identity for achieving this along with appropriate policies. It should be used with S3TransferUtility and S3TransferManager in iOS and Android SDKs. That would allow for background uploads and downloads as well. Cognito vends temporary credentials for access to AWS resources and is free. Also, you could federate it using UserPools or providers like Google, Facebook if you want secure access.
Thanks,
Rohan

Options to securely authenticate mobile access using OAuth2

We're currently in the process of implementing OAuth2 to secure our new API and not sure how to securely provide required functionality. We need to allow the following from a mobile device:
Immediately after downloading the app the user is able to take a picture and submit it without having to first log in.
While we want to allow anonymous user access, where a user does not need to log in or register to use certain functionality, we do not want to allow unauthenticated access to the API. This would normally be accomplished using the client credentials authorization flow to obtain and app access token, however this requires knowing the client secret. From what I've read, a mobile device is not considered a trusted client and should not contain the client secret, and hence should not be able to generate an app access token on its own.
We've come up with a few options to accomplish this requirement, but would like some input on them:
Embed the client secret in the app. Doesn't seem ideal from a security standpoint, but maybe we're missing an obvious way to secure it? We're targeting at least iOS and Android.
Generate an app access token offline and embed that in the app. Still not very secure, but at least the secret isn't exposed.
Allow access to certain functionality using only the client ID instead of an access token. This may be the simplest, but it introduces an inconsistency and requires multiple ways of authenticating the client.
Build and use a companion web app to generate app access tokens for the mobile app. On the surface seems like a winner, but now you have to secure access to the companion app!
How would you securely authenticate access to an API using OAuth2 from a mobile device without requiring the user to first log in?
Agree with the comments on the Q. Either:
1.) Use Client Credentials grant type in OAuth 2 - with an embedded secret in your App. Understand that this isn't super secure and someone will reverse engineer it eventually. Ideally each client would get a unique secret - so you could revoke a client if they're abusing its use.
2.) Live with that API being open - thereby not requiring an OAuth 2 access token at all. Maybe that API would be known only to your app - but again, it would only be a matter of time before someone reverse engineers it.
My group is having a similar discussion. Users can get the app and browse a catalog without having to sign-in. The catalog and other data is accessed via an API and we would like to force users to have an access_token for all calls.
Our current thinking is to
Always force the App to exchange a common clientId/secret for an access_token. So the app would get an access_token even for anonymous users. This would be via the client_credentials oAuth flow.
If the user signs in, use the oAuth password flow. They would pass in clientId, secret, username, and password. We would additionally allow them to pass in their anonymous token so that we could transfer any history from their anonymous session.
So for example...
access_token = api.oAuth.client_credentials(clientId, secret)
catalog = api.getCatalog(access_token)
authenticated_access_token = api.oAuth.password(clientId, secret, username, password, access_token)

Categories

Resources