'How to securely send passwords between Android client and server side application?
My current Android application requires users to login with Username and Password.
The Android application calls a REST web service for user login and I do not want to transmit the password as cleartext.
How do I go about securing my users passwords so that the server side can Identify/authenticate each user?
I am currently trying to employ the Jasypt library as follows:-
ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
passwordEncryptor.setAlgorithm("SHA-1");
passwordEncryptor.setPlainDigest(true);
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
...
if (passwordEncryptor.checkPassword(inputPassword, encryptedPassword)) {
// correct!
} else {
// bad login!
}
however my server side is written in .NET and as far as I understand the Jasypt documentation the password encryptors employ a random salt.
How can I have my server side code match the hashed users password I am sending it?
All my webservices have HTTPS endpoints, does this guarantee that no one can "see" my users passwords "in flight" when exchanging for an access token?
Solution 1:[1]
You have to be careful about what you do. Consider implementing a common two-factor key-sharing algorithm, such as TOTP.
A pretty uncommon, but really good practice, is the client-side hashing. This of course doesn't stop the hacker from logging in to the user's account, but it stops them from obtaining the potentially reused plain-text password.
I recommend that changing E-mail and password are done under the reset password formula, such that E-mail/SMS confirmation is required.
And finally, as you do it is extremely important that the connection, where the login happens is secure, for example, https/tls.
Solution 2:[2]
If you use Https(TLS) then your password is inaccessible to anyone intercepting the network.
You should hash the password string in your server side code not in the client
Also you can use OkHttp CertificatePinner to pin Https(TLS) certificate to your connection for avoiding man in the middle attacks.
Solution 3:[3]
A good solution would be to avoid using the traditional Email/Password approach to authentication and go with what another answer here suggested of OTP or One-Time-Password.
Consider the user experience: typing an email and password on a mobile device is cumbersome and annoying and awkward. Then they have to remember their password as well? The average person in the Western world probably uses 10 to 15 apps per day and we want to tax their human memory banks for another password to awkwardly type onto their phone while they are on a packed subway train?
Although it's deceptively challenging to put together, consider One Time Password. With it, a user enters in a phone number as an identifying token.
In theory, every single user has their own unique phone number and thats easy for a user to remember. Since your user is on their Android device, makes sense so far, right? And no awkward typing of email and password.
After they enter their phone number, we then text them a code to the mobile device, which is a 4 to 6 digit number. The user enters that code in the application, thereby proving they are the owner of the device that the phone number is tied into.
The benefit of OTP over Email/Password is that it requires very little memory on the users part. And yes, it's even better than OAuth because what if the user never signed in to a Gmail account or Github account via their mobile browser? Then they are back to Email/Password awkward style authentication for mobile device.
One-Time password is user friendly.
But you say okay, but is it secure and more importantly to the question: How can I have my server side code match the hashed users password I am sending it?
Right, so One Time Password technology is always an ambitious project to undertake IMO.
So we need to persist the code that the user should be entering into the device so we can compare it at some point in the future. When you generate a code, save it to Firebase so at some point in the future you can reach back out to Firebase and say the user with phone number 212-555-1212 just sent you the code 1234, is that the correct code?
So, the way Firebase works with OTP is you can store the code in Firebase. The challenge though is actually texting the user a code. This is an actual SMS message. To handle that, you can't use Firebase alone, you can integrate the extremely popular Twilio. Twilio is all about interacting with users via phone SMS messages and so we can make use of Twilio to text the user a code.
You can also take care of authentication or user system inside of Firebase. Once the user enters an OTP, we generate the JSON Web Token through Firebase.
So all the JSON storage and all the info that reflects who the user is, all that can be saved on Firebase.
But there is another part to that question I have not answered:
How do I go about securing my users passwords so that the server side can Identify/authenticate each user?
Okay, so you need to compare the code on some server. It can't be Firebase because Firebase is simply a datastore, it is a place to store JSON data, it does not give us ability to run custom code.
So do you write a server for the comparison of codes? We do NOT want to do this comparison on the user's device.
So what do we do? Also, how do we generate a code? Don't use the user's device for that either.
So where do we generate the code? We know to use Firebase data storage to store the code, but how do we generate it?
That's a good job for Google Cloud Functions.
So Google Cloud Functions are code snippets that run one time on demand on Google servers. GCF have tight inter-operability and integration with Firebase data stores.
We can add some logic or processing to the data sitting inside of Firebase. GCF will allow you some custom logic to generate your codes and save them to Firebase and GCF can also compare the code once the user sends it in.
AWS Lambda and GCF are nearly identical in functionality so that could be an option as well.
Solution 4:[4]
There are couple of things you need to consider while implementing authentication and authorization between client(Mobile app) and server.
Firstly, what authentication and authorization mechanism does your server have to request api endpoints? (Is it Two-Factor Auth? Is it bearer token (grant-type username and password) based? Is it bearer token (grant-type access-token) based?
Secondly, as you have mentioned server programming is .Net based but can you be more specific whether your service layer (Api ) written in WebApi 2 or OData ?
Finally, does your server allow to communicate with or without SSH i.e. HTTP vs HTTPS? If it's with SSH then its okay to transfer user credentials i.e. username and password over othewise it will be never secured to transer credentials over HTTP.
Then only it comes at your end i.e. in Android Mobile App to impelement the authentication and authorization mechanism as per server requirement to communicate with api endpoints.
For example, my server requires to implement token-based authentication (bearer token and grant-type password) to make every server request (GET, POST, DELETE, PUT) and I have implemented using retrofit client as like :
public Retrofit getRetrofitClient() {
// first add the authorization header
OkHttpClient mOkClient = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "XXXXXXXXXXXX")
.build();
return chain.proceed(newRequest);
}
}).build();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.client(mOkClient)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build();
}
return retrofit;
}
and my service is
public interface LoginService {
@POST("/api/token")
@FormUrlEncoded
Call<TokenModel> getToken(@Field("username") String username,
@Field("password") String password,
@Field("grant_type") String grantType);
}
Now I can use this token in every request to commuicate with server. I don't need to transfer username and password over public internet rather I use just token and it has 24 hours expiration ( as server has implemented this token expiration date).
Hope it helps you to understand the authenticaiton and authorization mechanism between cleint(Android Mobile App) and server.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | ucMedia |
| Solution 2 | MRShafiee |
| Solution 3 | halfer |
| Solution 4 | Ishwor Khanal |
