Security of logging in with phone number only, plus SMS code - php

I am building a cross-platform app and using PHP and MySQLi. Users sign up with either their Facebook account or phone number. If they choose phone number, they enter their number and an SMS is sent containing the verification code. The user enters the code and an API token is sent back to be used across the API requests. Tinder (for example) is this way.
I am considering Twilio for the verification.
My issue comes down to the security of this login process. Can a malicious user just rapid-fire the login request that creates a verification code over and over again... sending plenty of SMS and costing me a fortune on my Twilio account? Should I only allow so many attempts? Can a bot just eventually guess the code?
What is the security behind Tinder's API?

things to consider:
1- limit request per phone number
2- limit request per user (by ip)
3- use captcha (only after second attempts to keep your app user friendly)
4- use honeypots
"can a bot guess the code?"
verification codes should have a time constraint. after like 2 mins they should be invalid. time constraint and request limiting should make it very very unlikely for a bot to guess the code.
if you are using laravel it already have rate limiting middleware (limit by ip).

Twilio developer evangelist here.
I agree with all the things that Shalior says in their answer, so I'm not going to reiterate that.
What I wanted to share was this article on falsehoods programmers believe about phone numbers. It is a good reminder that phone numbers don't necessarily uniquely define a user, and worth keeping in mind if this is your intention for a passwordless login.

Related

How to restrict firebase phone number verification SMS to be send to only registered phone numbers?

Firebase phone number verification authentication is triggered by the user from the client-side SDKs on my website I am developing. Is there a way to write code such that the firebase api:
a. sends SMSs to only registered phone numbers (existing registered users) and
b. not send SMSs to unregistered phone numbers (anonymous users)?
This is to prevent data abuse by anonymous users to my website.
There is no way within the Firebase Authentication API to limit what users can authentication through SMS, or any other provider.
The logic here is that in order to know whether a user is authorized, you first have to know who that user us, which already requires them to authenticate.
This does indeed means that a malicious user can make calls through the API with your configuration data. You'd then typically prevent those users from accessing your application by a further check, for example by having the list of approved phone numbers you mention. The difference is that this check happens after the authentication step, and not as part of it.
Firebase has abuse prevention methods in place already, so there's usually nothing you need to do beyond calling the API and protecting your backend resources. If you suspect you're seeing abuse on your project, reach out to Firebase support for personalized help in troubleshooting.

Secure SMS Sending API endpoint

Explanation
I have an API running on Laravel 5.8 that uses Nexmo Verify API in order to send a code by SMS for two things :
(1) User account creation (check phone number before creating the
account)
(2) Forgotten password (check code sent before entering a new
password)
This PHP API is used by an iOS Application and an Android Application.
In the first case (1), I have to check that the phone number does not exist before sending a SMS.
In the second case (2), I have to check that the phone number exists before sending a SMS.
So, I may have two API routes :
One checks if a phone number already exists, so that the mobile applications can display the next page or display an error.
The other one simply sends a sms code to a phone number.
Problem
The problem is that we can have a route that looks like /api/phone/sendcode and anyone can call this route directly without using the mobile application if they find what the endpoint is (it's just an API after all). It can be easy to use this route to spam.
Or, they also could call a route api/phone/exists tons of time to try to get all existing users.
Question
How can I secure the endpoints in order to avoid people using them directly to SPAM or to check in a loop if an account exists ?
I already have a throttling system to block a specific IP address to request an endpoint more that X times in a minute, but I think this is not enough and can be bypassed (using a proxy or whatever).
Also, I prefer to avoid using Captcha.

How to stop url request to validate credit card number

I have a website (PHP Laravel site) that uses Brainstree to process credit card payments. Today the site receives A LOT direct request to 1 url that passes in credit card information. It seems the hacker figures out our parameters and is using my site trying to validate their stolen credit card numbers.
Here is an example of a request.
http://mysite/renew?card_nubmer=42693111111111&ccv=014&expiration_month=11&expiration_year=2019&first_name=beqnykit&last_name=fozwgfrpn&postal_code=44101&type=visa&price=12year=1&country_name=USA&currency=%24
It is causing the CPU usage to be 100%, slowing down my site.
Before our code was processing the request and display an error page. Now it validates the request and redirects invalid renew request to log in page. The CPU load is still 100%.
What can I do to stop this or stop the CPU load, at the least?
Enable the use of CSRF field, it's a must. You're saying you began handling the request as POST, so that's fine.
This route also has to be available for authenticated users only. Add a proper middleware if you haven't yet.
As for additional protection I would recommend to use some throttle middleware. Consider using this package or something similar. It will not allow to use the method more often than the number of times per minute you specify. https://github.com/GrahamCampbell/Laravel-Throttle
Here is the update. The hacker really analyzes the site. It create free users. Each free user uses a credit card to submit an order for a paid membership. We are a target because the amount is small. Using POST doesn't fix this hack. So we have added account activation email and recaptcha in account creation and order page. Luckily, it is stopped pretty quickly. I am just putting the info here to share experience. Thanks for all the help!

Alternative method for 2 factor authentication

Scenario: I want to create an app where users register accounts and a server sends them a one time pin to verify their contact details via SMS. User enters the code received to verify their details.
However, sending an SMS costs money but receiving one is free and my SMS gateway lets me read incoming SMS messages.
So I could create a screen in my app that lets the user send an SMS to my gateway with the gateway number and message prefilled (eg. "Hi, please activate my account with code: 34GKTT551T"). User only needs to press send.
Instead of having the user type in a code they've received and verifying the code on the server, my gateway picks up a code sent by the user and sends the message to my server which then verifies the code and thus validates that the users phone number is the one they entered on registration.
Question: Is there anything fundamentally wrong with this approach?
What are the pros and cons of doing things this way? Yes, I know SMS messages can be faked but it's harder than faking an email which could also be used. I would not consider this an alternative to proper 2 factor authentication but this approach worth doing as a lower cost alternative that doesn't require users to do anything else special.
PS. This is my first question on stack overflow so be nice.
No this is not secure as the sender of an SMS can be easily faked. Take these instructions for how to achieve this on Kali OS.
There are also services such as this one.
All it would offer is a very thin layer of security against people who have the user's password but do not know the above information or the mobile phone number of their victim. The phone number of their victim may be achieved via other means such as social engineering. It may work if there is a separate phone used for the sole purposes of 2FA, however why not go with using Google Authenticator API, which is free (Google Authenticator app available for iOS and Android)?

Preventing abuse to an invite system

recently I helped some friends ship an invite system in their website that works like this: A user creates an account, we send a verification email and when he verifies the e-mail he gets one free credit to spend on the website. In addition to that, he has personalized links he can share on social networks or via e-mail and when people register using this link (e-mail verified accounts again) he gets one credit per invite. Much like the invite system on thefancy.com or any other reward driven invite system on the web.
Lately we see elevated rates of fake user account which probably are automated. The registration page features a CAPTCHA but we're aware this can be bypassed. We also see elevated rates of users creating disposable email addresses to create accounts following specific invite links thus crediting one legit users that onwards uses the free credits he earns.
I am looking for an automated way to prevent such kind of abuse. I currently investigating putting rate limits on invites/registrations that come from the same ip address but this system itself has it own flaws.
Any other production tested ideas?
Thank you
Edit:
I've also proposed 2 factor registration via SMS but was turned down due to budget shortage.
It seems you need to require more than just a verified email address before a user can send invites, ideally something that shows the user has participated in your site in some way. Without knowing what your site is it's hard to give specifics, but the StackOverflow equivalent would be requiring users to have at least X reputation before they can invite others. If you're running a forum you could require that they've made at least X posts.
I'd also suggest a small time limit before new accounts can invite - e.g. they have to have been a member for at least X days. This complicates automated invites somewhat.
An extremely simple method that I have used before is to have an additional input in the registration form that is hidden using CSS (i.e. has display:none). Most form bots will fill this field in whereas humans will not (because it is not visible). In your server-side code you can then just reject any POST with the input populated.
Simple, but I've found it to be very effective!
A few ideas:
Ban use of emails like 'mailinator'.
Place a delay on the referral reward, allowing you to extend fraud detection time period, giving you more time to detect bogus accounts and respond accordingly.
Require the referred user to create a revenue generating transaction before you give out any referral rewards (I know that might not be a shift you can make) - possibly in turn increasing the reward to account for the inconvenience to the referrer (you should be saving money through decreased fraud so not a hard sell).
Machine learning. Ongoing observations and tuning with your fraud detection. The more data you have the better you will be able to identify these cases. (IP addresses as you mention.) Shipping / billing info even more telling if it applies - beware adjacent PO boxes.
Add a CAPTCHA test to the confirmation page. I would be wondering if your CAPTCHA is sturdy enough if it is getting bypassed somehow. You might consider using the (hateful) reCaptcha which seems popular. A CAPTCHA on the confirmation page would reduce the risk that a 'bot is submitting the confirmation page. In other words, it would implement the idea of client interaction with the site after registration. A similar method would be to ask for the registrant's password.

Categories