How to secure an app built on phone-number registration? - security

I want to build a mobile app that requires the number of the user to be filled in. After that, the phone number is sent to a server, the server generates a random verification code that corresponds to this phone number. Then, this verification code is sent via SMS to the user. Next, the user sends the verification code back to the server to ensure that he/she has entered his/her real phone number and not anybody's else.
I was wondering how do you really authenticate against the server if you only have a phone number and nothing else? I mean, in the typical scenario you have a username and a password that are checked on the server and if both of them are correct you can have access to the server. But in the case of a phone-number registration, you have only a phone number and if you authenticate with it only, it means that anyone who knows your number or just picks it out, can pretend to be you.
If you send some sort of a unique device ID, that means that you won't be able to use your existing account anymore, for example, if you happen to change your device with a new one.
So, how do you solve this issue?

The pattern is always: client provides proof of something they have, in return they receive an identifying token. In a typical username/password scenario, this means the user proves that they have a secret (username + password), in return they'll typically receive a session cookie. In your case, the user proves that they are in possession of a specific phone, in return you give them a session token or other identifying token. The client holds on to this token and uses it to identify themselves to the server.
You're relying on the principles of the telephone system to make sure that's a uniquely identifying characteristic. You're basing your security on the assumption that only one person can receive messages for a specific phone number at any one time, and that you need to be in physical possession of the phone at the time of login to complete the proof. Of course you require this proof every time the user logs in. You do not let them register once with an SMS-loop, then afterwards you just ask them for their number and let them through.
If a user wishes to log in, they must proof they're in physical possession of the phone in question using the SMS-loop, then they'll receive a token. Period. That's the way it goes. No other way. The client (app) must hold on to the token for as long as it wishes to stay logged in. Obviously, you probably want this to last for quite a while and not require the user to do SMS confirmations all the time.
This obviously brings us to the topic of token theft, which can be a real issue. The token must be kept secret, since it essentially allows proof-less authentication. You may want to think about signing that token using some unique identifier specific to the device it's for, or encrypting it while it's stored on the device or other measures to make sure it can't be nicked from the device while it is stored on it.

As deceze points out, the best way to ensure the comm is safe is to use a temporal token signed with the device id. If the user logs out, changes device or reinstalls the app then they must go through the SMS verification process again to ensure the SIM cards is still in their possession. Keep in mind that the SIM card and device have different udids. To simplify this you can use RingCaptcha SDK on your app to generate the token, verify the user possesses the SIM card and store that token or id temporarily. Use the phone number as an identifier - similar to a username - and the temporal PIN code as the password. That pair plus the token will give you enough security that the device and SIM card are joined.

Related

build a One Time Password authentication server

Problem
In our system we have:
Two apps: a backoffice in reactjs and an app for user in react-native
An API (with postgres db)
Hubspot (user informations, phone number, etc.)
We want to add an authentication server to secure our user data and allow user to connect to the mobile app. That server would provide tokens and a link between Hubspot (that carries user informations) and the user in the API db. The db would store only hubspot user id and the api user id and some timestamp. We want to use a One Time Password using text messages.
The workflow would be something like:
the user want to connect to the app (for the first time or not). The app is requesting a phone number.
the phone number is sent to the auth server that checks if it exists in hubspot. If the user phone number exists but nothing yet in the database, that means we need to create a new user (in the auth server database AND in the api). If the user number exists and already in the database there is nothing to do. In both case, a token is generated and the user is able to connect (still need to understand how to do that). If nothing exist in hubspot, the user wouldn’t be able to authenticate in the app.
Questions
Am I going in the right direction? Creating an authentication server, is it a good idea or completely useless? Should we implement our logic directly in the API? The system is about medical information and data should be protected.
Concerning the OTP, what should we send to the user if the phone number actually exists? The auth token or a random string to require the actual token?
the phone number is sent to the auth server that checks if it exists
in hubspot. If the user phone number exists but nothing yet in the
database, that means we need to create a new user (in the auth server
database AND in the api). If the user number exists and already in the
database there is nothing to do. In both case, a token is generated
and the user is able to connect (still need to understand how to do
that). If nothing exist in hubspot, the user wouldn’t be able to
authenticate in the app.
I do not think sending the phone number to the auth server is a good idea, instead you generate a code and save it on some backend server or some backend database and then text the user the same exact code. The reason for saving the code on the backend is to compare it to the one the user provides at some point in the future.
That is a unique identifying piece of information, not a phone number, peoples' phone numbers change all the time.
The user presumably receives the text message, that is the only reason we need the phone number for to send that text message and they can enter that code back into the application.
So the user sends us the correct code and that comes to the backend server. It's then compared on the server and if the user entered the correct code, send them some further identifying token, such as a JSON Web Token that identifies the user for future follow up requests.
This is what it means to be authenticated. Once the user successfully enters the token, we provide a user with a JSON Web Token to specifically identify them and say, hey this user did correctly enter a one time password, here is some identifying information on the user.

SMS verification : what if user phone number changed?

I’m building an application and I’m thinking about asking user phone number to send a verification SMS. Though, imagine if the phone number is cancelled and attributed later to someone else. Then, the new person would be able to connect to my app in the name of the old one...
So is there any way to prevent this behavior ?
I want to make it like tinder : sign up possible by 2 different ways : (facebook connection and phone number) or (phone number and mail)
I have another question : I see that many sms sending services are not free (all of them actually). If I make an api with these services, anyone can send a lot of http request to it and make me pay 0,05€ times 100000000 ? And I can’t rely on IP adresses because with 3G an ip is not associated with a particular person...
To your first question:
You are describing Two Step Authentication (aka Two Step Verification) which you can read about in the Wikipedia page: Multi-Factor Authentication (MFA):
a method of confirming a user's claimed identity by utilizing something they know (password) and a second factor other than something they have or something they are. An example of a second step is the user repeating back something that was sent to them through an out-of-band mechanism.
You are correct that a phone number can change owners (as can an email address though over a longer time period on average). You are using their phone number as that out-of-band mechanism described above.
If the user has recently authenticated with their password, when you send the user an out-of-band code and they re-type that into an input box you have some degree of confidence that the end user both knows the password and has access to the SMS message and are choosing to trust that association.
You will need to consider if, and for how long, you can trust that association within the security context of the use case.
For example, adding two step verification when detecting the end-user has just authenticated on a device you have never seen before is a nice additional protection. However, using the out-of-band SMS verification in account recover could open up a big security hole. You do not want to bypass the authentication with something they know (password) in a password reset flow by simply having access to that SMS number. SMS is also not an appropriate mechanism for one-time-password (OTP).
If you want to offer you users more protections on their accounts look into implementing true MFA with software tokens (eg. Google Authenticator, Authy, etc.) and hard tokens (eg. FIDO U2F devices such as Yubikey, Google Titan, etc.).
To your second question:
You are correct, IP-based limiting is insufficient. With SMS services you are likely going to be making a server-side API call to the SMS provider. First check to see what security features your provider has out of the box. Next, protect your endpoint that is triggering the API calls to the SMS provider.
Rate limit the number of SMS messages to any one given recipient (eg. no more than X SMS messages to a single number per Y minute window)
Rate limit the number of SMS messages one person can make to different numbers (eg. no more than X different phone numbers per user per day).
Do not allow unauthenticated requests. The user should have already completed the first authentication step (something they know eg. username/password) before performing the out-of-band SMS step.
Protect the SMS form from Cross Site Forgery Requests (CSFR). Your back-end should only make the API call to the SMS provider if it knows the request came from your front-end and not another host.
Protect the SMS form from bot attacks. There are many approaches with Google ReCaptcha being one of the more common.

Node passwordless login from seperate device

I am using the nodejs passwordless (https://passwordless.net/) library for passwordless login. One of the features is a link sent in an email that opens the logged in page in the browser. Works great.
What I would like to do is have it so that if the link is clicked on, on one device, and the page that the user entered their email is open on another device, then that page would also login, using some cookie or something.
The reason for this is to add even more convenience to the concept of passwordless login - by being able to click on the link on a phone you dont have to go to another tab in your browser on your computer.
Do people have any other thoughts about making passwordless login as seamless as possible?
What you're asking for isn't possible because it "begs the question" that authentication is designed to answer. Namely, "Is this client application operating on behalf of a user registered with this service?"
Let's walk it through:
Device 1
The user visits your website for the first time.
The service sets a cookie with the id of a new, unique session on your website (or app).
The user submits their email in a form.
The user receives an email with an URL+token, token courtesy of Passwordless.
The user clicks on the URL.
The service validates the token, again via Passwordless, and marks Device 1's session as authenticated.
The effect of this workflow (esp. steps 3-5) is to let you infer a vital piece of information: that whoever is contacting this website has control of the provided email address. Now let's look at another device.
Device 2
Some user visits your website for the first time.
The service sets a cookie with the id of a new, unique session on your website.
So we have a device, with a cookie, but now what? Literally anyone in the world could have just pointed a web browser or app at your site. We need more information. So we could ask for an email address:
The user submits their email in a form.
Now we have an email from Device 2. But we have no idea whether this is legitimately the user who controls this email address. It could easily be an attacker, someone after your service, after this user, or maybe just a spammer with some bots.
It's not until we get to step 6 in the original workflow that we have enough information to know whether this device is being used by the same user as on Device 1. But once we've gone that far, the user has just logged into Device 2! At that point there's no need to "log them in automatically" from Device 1 because they just authenticated themselves on Device 2.
I think this might be possible.
I don't have a cooked recipe but some direction for your exploration could be :
You need to set allow reuse tokens before setting your token store. This can be done by allowTokenReuse:true.
Somehow make sure first 2 or more devices gets the same session. This could be done by sharing sessions.
A more solid advice would be using sockets to track connected clients. You may want to check the post here
I found a awesome article to share and sync sessions between socket.io and express. Check here
Pls share your explorations of you can. I am thinking to use sockets aswell.

J2ME High Secured app for m-commerce

I am creating a j2me application for mcommerce, which uses mobile internet(gprs). I wanted make it more secured by binding the application to the SIM card and the device. That is a user should be able to login to the system, only using his/her SIM card or from the registered mobile number.
To achieve this I need to fetch the mobile number.
So, on login i thought of Triggering an SMS from the server with a key, which the application reads and uses the key for the entire session. Here the challenge is, that sms should not go to the inbox.
Any suggestions pls?
Yes it can be achieved using the Wireless Messaging API. Have the MIDlet set up a server connection on a chosen port number, then send the SMS to that port number. It will go straight to your app, bypassing the inbox. If you use the Push Registry, you can even make the SMS start your app if it is not running.
It doesn't matter if the user sees the number in his/her inbox.
As long as the key is only used that session, it is her/his responsibility to not share the key with others.
The one thing you make sure is that ONLY the person who owns the SMS phonenumber gets the key and is able to log on.
This doesn't take care of the phone being stolen though.

Is a user account activation email without a secret kept in the DB reasonably secure?

I want to create a newsletter app and users will naturally have to confirm that they signed up for the newsletter so we don't spam them if some bot entered addresses.
My idea was to simply send the user an email that contains a link that has a secret in the url, which is a hash of the email address and some secret sitekey.
My questions is the following:
Can someone by registering a few accounts and thus receiving the hash of the secret with his address, guess the sitekey and thus register every email address she wants?
I don't see anything that could be gained from doing that, but if it is very easy, chances are someone will do it and I get blacklisted.
My reason for not storing a non activated user account are simply that I don't want to purge them from the DB every x days.
If you ensure you use something like sha1 with a completely random salt/sitekey, then it would be futile to attempt to reverse engineer the sitekey with a dictionary attack.
If someone did want to synthesise their own hashes to register arbitrary addresses, a more effective use of their time would be to gain access to your server to read the source code :)
I think it would be best to generate a random secret and keep it in the db. That way there is nothing that can be guessed. (At least not nothing that grants permission to add any email).

Resources