How to protect a reset password feature? - security

I want to implement a reset password feature in case users lose their passwords. But I'm worried about someone being able to make a lot of these requests for a single or multiple email addresses that don't belong to him, which would be annoying for the actual owners of those addresses, and I would end up blacklisted.
What can I do to secure this feature against that? Set a limit of valid emails sent per ip? (3 emails max would be fine I guess)

Why not simply add a CAPTCHA to the password reset request form? You could then limit the number of requests per email address and per day/week/month, but a CAPTCHA would keep bots away.

Assuming that you are writing an application meant to be used on the internet, where you cannot control registration of users, you can set a rolling limit on the number of password reset attempts that are attempted on a user account.
The rolling limit would be used to ensure that too many password reset requests are not sent out within a short duration. You can limit users to issuing 3 password reset requests, but only within 1 hour, or may be even 1 day; your business should be capable of determining the optimum value, especially if users can also issue password reset requests via other means (by sending emails or calling up a service desk).
Also, you can associate the generated tokens (I'm assuming that you are sending out password reset tokens with each mail) with a predefined expiry date, and all such tokens may be used only once. Tokens should ideally not last more than a few hours. Highly sensitive applications would also audit all password-reset requests in addition to the usual authentication attempts.
Finally, you can also establish limits on the number of password reset requests originating from a certain IP (this is a DoS prevention attack and wouldn't work against DDoS attacks). Needless to say, but the associated accounts should not be disabled in the interim, if an attempt was made to reset the password. Doing so, would enable a successful DoS attack where in an attacker can disable accounts by simply issuing password reset requests against a known email ID database. You will have to account for ISP proxies in establishing the limit, or you might actually hurt a few customers in the process.

I have seen other web properties introduce a new password reset system (much better than CAPTCHA) which provides some form of 2FA (two-factor authentication) where you can telesign into your account, in place as a back-up. User gets a one-time pin code sent to their cell, and enters that in. No spam filters to deal with, captcha forms to reload, etc... much easier. Prevents bulk registrations, spam, and generally seems to be more effective and user-friendly than alternative solutions.

Be careful about settings limits by IP. You've often got a single internet gateway exposing large number of users through a single IP (i.e. corporate networks).
If you're worried about the number of requests made to reset a particular address, this is more of a usability issue than a security issue. I'd be inclined to define an acceptable rate which balances not allowing too many reset requests with not making it too difficult to perform a reset (i.e. original email gets caught in junk so another is requested). For example, log the time of the request and not allow another one for another 15 minutes.
Pragmatically though, I wouldn't be too worried about this. There are endless ways to screw with someone via email if you really want to so unless there is something particularly attractive about exploiting your reset feature, I'd just be doing what most sites do and allowing resets when required and only actually resetting the password after the user receives the email and actions it.

Forgot Password Page Protection:
Show a success message when an invalid email is entered. When someone enters an invalid email, tell the user that the reset password link has been sent to your email (but dont actually make the code do anything). This will protect from hackers trying to identify valid accounts on the system.
Use A Captcha Phrase. To avoid malicious scripts from triggering many reset password requests for a large list of emails.
Reset password link for a specific email should not be sent more than 3 times (or so) per hour. This will protect from flooding the database with too many reset links stored in the database table and filling up the data disk.

Related

Denial of Service attack for One Time Password resend function

In our web application, we have a function where the user reset his/her password. Part of the process requires sending OTP via SMS. The thing is, we have a function in our page that allows user to resend the OTP in case it was not received due to certain reasons (sms provider error, network error etc.). Upon recent penetration testing, it was found that that the back end call for sending the OTP is vulnerable for DoS attacks. Hackers can run it to flood users with SMS.
We already have a mechanism in our firewall which detects automated attacks for denial of service. The problem is, there is a minimum limit of requests per second for the firewall classifies it as an attack. (e.g. 100 requests per second, the FW blocks it but anything below, it allows).
Lets say hacker did a program to resend otp via sms per second, the firewall would not be able to detect it. Another option we can do is handle it programatically but we can't think of a best way to do it. Can anyone advise us on this? We can't just limit the no of times an OTP can be resend because we are worried of its effect in user experience.
Two things come to my mind:
Take Macuistin's idea but make the timeouts grow over time. I know I wouldn't want 3 text messages a minute. After X number of messages don't send anymore and have them contact support. If this is a legitimate user, after so many messages something isn't right and you should just stop.
How about adding a step before this, send a link to the email address of the user with a one-time link, click on the link will send them to the page to enter in the OTP that triggered on the link (there could be a resend link on there as well which would not trigger another email).
Have you looked at the timings in real world use cases?
For example, if a real user takes 20 seconds before pressing retry then you could add that restriction to your service without real users knowing that the restriction is in place.
That doesn't mean that you couldn't accept another request before this time, it could just be queued until the timeout has passed.
This will not possible through WAF, Here you can use Captcha for failed attempts.
Captcha only pop up when particular limit cross. You can set limit on IP, UserID, and session variable.

Best practices for passwords on registration?

I have a website which users register an account. On the registration field, the form fields are:
Name
Email
Confirm email
Username
But there is no password field. When they hit submit, they are emailed a password which is very complex, such as LHJVjhwnv%uu5 or RbWM9!jeDZUQb.
I have appealed to my developer to instead make it so that the users can set their own password on the registration form. To confirm that password on the form, and then be sent a confirmation link to their specified email. Then this way they can at least log in to their account and verify their email via confirmation link. Or if they didn't, every time they log into the site it could remind them to verify their email etc or else they can't do much on the site (example). This way even if they don't get the confirmation link, they can still update their account email to a different email and have it resent. At least at this stage, they can log into their account, instead of not at all.
The response I have received from the developer is as follows
"The problem with providing the password on registration is that
you'll have loads of fake accounts. So people that just register with
a non-existent email address. At least with the email validation
you're proving the user exists, to a certain extent. If they register with the wrong email, they can just re-register."
I'd like to ask you all if the current approach the developer has employed is acceptable?
If not, what are some good reasons I could use to convince the developer to change?"
I've tried to explain the following
Every day there are 9-10 people who register and then directly use the "password reset" form right after. This form involves them putting in their email address that they signed up with, and then it emails them a link to SET a new password. So if they are setting a new password anyway, why not just have them set it in the first place on the registration form? Why would there be 9-10 people every single day using the password reset field, directly after registration? I'm pretty sure its because they are seemingly struggling with these complex passwords (which I am not against) that are being emailed to them and are missing a key or character, or do not seem to be aware of copy/paste or something like that. If they could just set their own password the first time around, they wouldn't need to run to the password reset field right after because of their emailed password not working. I thought it was weird how everyday theres always password reset emails. Not for everyone, but a good 9-10 people a day ever since I started using Mandrillapp to track the outgoing emails. This is backed up by the next point.
Every day there are at least 2-3 people who fill out the contact form indicating that the password they received is not working. Could all be avoided if they just could set it on their own. There may be even more that just don't bother contacting.
Out of nearly 8000 accounts, 50% have never logged in. My strong suspicion is that the Registration email containing their password goes to their junk folder/spam folder. This is despite me having proper SPF, DKIM, etc setup. 2 months ago, I decided to start using Mandrill to send mail to ensure it goes to the inbox, but still there's at least 1-2 people/day that say that they did not get their email.. which perplexes me. If they could define their own password, they wouldn't have to worry about waiting for their password via email, or not getting it entirely. This just further highlights my initial concern.
Thank you for your time!
I assume you already have a working password-reset page in place, so you can use just the same code to do the registration:
Let the user register with his email.
Send a link with a token to the user, a hash of the token is stored in the database.
If the user clicks the link and if the token is valid, welcome him and let him enter his own password.
This is exactly what you already have for password resetting, your site becomes no more (un)secure because an attacker could as well use the password reset function.
Of course weak passwords are a problem, so rejecting weak passwords is a must. Again this is the same you would have to do on the password-reset page. For password-resets you wouldn't send plaintext passwords neither.
Unconfirmed accounts can be deleted after a certain period, it means the user didn't do anything with it. If necessary the user can register again. This only works if the user is not allowed to login before doing the confirmation, what supports the procedure above. Of course it depends on the website if this confirmation is that important though.
The main reason not to send passwords in a mail is security: Mail isn't a secure medium. If you put a password in there, then many people can see it - consider allowing people to use your service without any kind of password instead to understand what I mean.
The main drawback of allowing people to chose their own password is that 95% will use 123456 or password.
Most big sites use this approach to balance security, business needs and comfort:
Allow user to set their own password. Reject the most simple ones (there are libraries for this). Note: Complex password rules drive customers away.
Send a confirmation link via mail.
Don't allow login until the link has been clicked.
If they try to login anyway, tell them that they have to click the link first plus provide a "send confirmation link again" link in case the first mail was lost.
I have appealed to my developer to instead make it so that the users can set their own password on the registration form....
This opens you up to a plethora of weak password and reuse attacks. Reuse has been empirically studied and reported between 50% and 76%. Other academic studies have stated nearly all users (almost 100%) reuse passwords.
So assigning passwords helps with major practical problems. After you assign the password, then you are subject to the same attack, though because a user may reuse the assigned password on another site.
...
I'd like to ask you all if the current approach the developer has employed is acceptable?
Yes, its acceptable as long as the password meets security requirements. I even prefer it, especially when user selected passwords are not checked against bad password lists.
Bad password lists are important because we know attackers use them. There are literally millions of passwords on them because of all the past breaches (did I mention password reuse is a pandemic problem?). The lists are easy to find, and one researcher recently released his list of 6,000,000+. See How I Collect Passwords.
Aaron is correct about email and plain text. You can actually place another security control to limit the exposure. Namely, require that your mail server use SSL/TLS or fail the connection.
Or, generate the password and display it to the user on the screen. Instruct the user to print the password so they don't forget it. I even tell my users to write them down and keep them in their wallet or purse.
The primary threat is a network based attacker attempting to gain unauthorized access to the server through weak/wounded/bad passwords. So an out-of-band/out-of-channel email is not too great a concern. And a lost wallet or purse is not too great a concern. The concern is the network based attacker guessing passwords or using {username,passwords} tuples from breaches of other sites.
Every day there are 9-10 people who register and then directly use the "password reset" form right after. This form involves them putting in their email address that they signed up with, and then it emails them a link to SET a new password.
OK, that's a security defect since the user can circumvent the security control.
For what its worth, I regularly use a random password generator to generate passwords for accounts. I don't even bother writing them down. When I need to access the account, I simply go through the Lost Password process.
That's how low value these things are to me. Every damn site wants a user to manage an account and password. I'm tired of expending the energy to manage all the accounts, so I don't even waste the cycles on it.
The problem with providing the password on registration is that you'll have loads of fake accounts. So people that just register with a non-existent email address. At least with the email validation you're proving the user exists, to a certain extent. If they register with the wrong email, they can just re-register
OK, so this is a different problem. BOT registrations are usually mitigated with a CAPTCHA. I've never really studied what to use for Real Users/Fake Accounts.
What is the benefit of a fake account? It seems to me the user is trying to get half pregnant. They either have an account, or they don't have an account.
Out of nearly 8000 accounts, 50% have never logged in. My strong suspicion is that the Registration email containing their password goes to their junk folder/spam folder. This is despite me having proper SPF, DKIM, etc setup.
Well, that's a different problem (that you should confirm through testing). This speaks to displaying the password for the user and telling them print the page.
There's a lot more to the subject of password management. You should read Chapter 7 of Peter Gutmann's Engineering Security.
I have appealed to my developer...
Finally, you are the boss. Fire the developer or contractor if they are not following instructions or coding against requirements. I'd be damned before I begged someone who I was paying for services.
Programmers are a dime a dozen, and you can find plenty of them at places like Rent-A-Coder. The Indians and Pakistanis work for next to nothing (under $10 USD per day in some cases). I don't know how they can work for so little and survive...

Time limited, or one time use, password reset tokens?

Users forget passwords, and (nearly) all membership sites need a way to help users get back in.
I'd like to implement the common scenario:
User hits site, tries to log in, can't, and realizes they forgot password - crap!
User enters email address and clicks "forgot password"
User gets email with a password reset link
Here's how I'm planning to implement this (C#/ASP.NET MVC):
When the user enters email and hits "forgot password" button my site will generate a GUID, store it on the member's entity in the DB (member.ResetToken), and email them a link with that GUID in the url (the email sent will inform them they can use this link to one time only)
User clicks the link and my site looks up their account based on that member.ResetToken from the url. If their account is found show them a password reset form, and when they complete the reset it clears the member.ResetToken from their account.
Here's my question: keep it like this (in which they can reset their password with that link at any time, now or in the future) or add a timestamp to limit how long they have to reset their password?
From a UX perspective the ability to reset your password whenever you're ready is great, but I want to make sure I'm not overlooking some security issues this could raise.
Your scheme actually works, but there are some points that could be improved. But first to your original question about the time limit:
Let's ask the opposite question: Why should a token remain valid infinit?
There is no advantage, when the reset-link can be clicked two years later, either the user clicks the link in about an hour or he has probably forgotten about the link (and can request a new one if necessary). On the other hand, being able to read the e-mails doesn't necessarily mean, that an attacker must hack the e-mail account, there is for example the open e-mail client in the office, a lost mobile phone, a backup on the (lost) USB drive...
The most important improvement is, that you should only store a hash of the token in your database. Somebody with access to the database (SQL-injection), could otherwise demand a password reset for any e-mail address he likes, and because he can see the new token, he could use it to set his own password.
Then i would store those reset informations in a separate table. There you can store the userid, the hashed token, an expiry date and the information whether the link was already used. The user is not in a special state then.
Maybe i misunderstood this point, but the reset link should point to a special page for password resets. When the user goes to the login page, there should be no special handling, the login page should not be aware that there is a pending password-reset.
The reset token should be unpredictable, this can be achieved best with a really random code, reading from the random source of the operating system.
So, there are a few problems with this approach that I was trying to elude to in my comment. When you store the "confirmation token" in the users password, you have just basically destroyed their password.
I, a malicious person, can then take a big giant list of email addresses and a bot net and flood your server with password reset requests and lock out your users from their account. Sure, your users will get an email for the reset, but if I can reset passwords fast enough, there may be a backlog of emails (or, if you do it synchronously, i can likely DoS the entire application).
I, a normal user of your system, may attempt to reset my password, and can't figure out why I'm not getting the reset email because I don't even know about a spam folder (or it never arrived). Fortunately, I just remembered what the password was, but it doesn't work anymore since the password is now an opaque GUID, and I'm basically dead in the water until I can find the reset email.
Here's the process you should use.
Generate a password reset request which you look up using a GUID, and you could likely also secure this by hashing that value with some private data and passing that in the URL as well to avoid a rapid attack. You can also lock this request down by making it only valid for a certain amount of time.
Once someone follows that link with a valid token and any other parameters you specify, they can then change the password, at which point you can now safely change the users password.
Flag the password request as having been completed, or delete it. You could also track information like IP address or something similar if you are really concerned about who changed the password if you are really concerned about it.
Send the user an email confirming that they have changed their password.
Also, just in case this isn't happening already, make sure you are hashing and salting the users password. It doesn't sound like you were doing that when you were just replacing the password with a GUID, so just double checking.
Users also forget to reset passwords (things happen). Being paranoid about passwords, I'd suggest limiting the link lifetime to 24 hours. This should be more than enough. It doesn't solve the problem of malicious intercept but it is better than nothing.
I would make the following suggestions:
Require some piece of information before the user is allowed to click the forgot password button. For example, require an email address and date of birth.
Ideally your user interface should not provide any feedback that allows a hacker to determine if his reset request succeeded. You don't want them farming your page for email addresses or DOBs. However this is a usability tradeoff, so whether you do this depends on how much security you really need.
You might also considering requiring a captcha which makes brute force and application DoS attacks much more difficult.
Expire the one-time token as quickly as possible. A couple hours is enough in my opinion. You should never consider email to be private-- it isn't, unless you are using a secure email technology (e.g. PGP) on top of the base protocol (most people do not). The last thing you want is for a black market to open up where your GUIDs are bought and sold, which is exactly what could happen if they have infinite lifespan.
Do not use GUIDs. They are not cryptographically random and are guessable. I suggest you use a cryptographic random number generator and translate it into base64.

Techniques to avoid the oracle attack on matching accounts info that a password reset system could lead to

Let's say you create a password reset system for your webapp. The system requires either a username or an email to send out the reset link to an account's email.
Consider these conflicting requirements:
Cracker A inputs into the system's form potential usernames (or emails) in an attempt to discover matches currently in the system.
Ideally, the system should neither confirm nor deny the presence of existing usernames and emails, giving exactly the same feedback to either case to prevent revealing matches.
User B tries to reset their password, but misspells, or worse, misremembers, their user name, such that it does not match any account on file.
As such, their reset request will never be fulfilled.
Ideally, their mistake would be made plain to them seconds after they request a reset, with a friendly message like" I'm sorry, we have no such username (or email) on file. You could try checking your spelling, or go ahead and create a new account." Otherwise, they may check their email, find nothing, wait, nothing, reset again, nothing, (because no match is available to send out) perhaps take their business elsewhere? If you're lucky, call customer service?
What ways are there to resolve these conflicting goals?
Edit:
After thinking the problem through, I'm considering that one way to solve the problem may be using email address only and if that email doesn't exist in the system, send out a "That account doesn't exist, here is a link to make a new account" to the email instead of the reset link.
That way, the user would always get informed, and a cracker could only get emails sent to accounts that they already had access to, which wouldn't be useful to them.
Make sense? Problems with that approach?
The usability for User B probably trumps the security risk for Cracker A, so the key is probably to limit what Cracker A can find out.
One way of handling Cracker A is rate-limiting the responses. User B will submit one request every 10 seconds (say) from speed-(mis)typing their name, and will do so from the same IP address. Cracker A will be trying to submit as many requests as possible in as short a time as possible, possibly from a botnet of many infected PCs under his command. If you always take (at least) 5 seconds to respond to a request, even when your system is perfectly capable of managing requests quicker, then Cracker A can only search a limited portion of the namespace in a reasonable time. Actually implementing this might be harder than I'd like to think it was.
Your system might need to be aware of attack patterns, and if there is a wide-spread attack fishing for responses, it should increase the time to respond. Such techniques require more intelligence in the reset response system, to detect where requests are coming from and how frequently. You might need to spot bad patterns in the IP addresses sending requests. If the same address sends many requests, especially if it does so after getting a match (response sent to given email address), you become rather suspicious of the IP address.

Preventing Brute Force Logins on Websites

As a response to the recent Twitter hijackings and Jeff's post on Dictionary Attacks, what is the best way to secure your website against brute force login attacks?
Jeff's post suggests putting in an increasing delay for each attempted login, and a suggestion in the comments is to add a captcha after the 2nd failed attempt.
Both these seem like good ideas, but how do you know what "attempt number" it is? You can't rely on a session ID (because an attacker could change it each time) or an IP address (better, but vulnerable to botnets). Simply logging it against the username could, using the delay method, lock out a legitimate user (or at least make the login process very slow for them).
Thoughts? Suggestions?
I think database-persisted short lockout period for the given account (1-5 minutes) is the only way to handle this. Each userid in your database contains a timeOfLastFailedLogin and numberOfFailedAttempts. When numbeOfFailedAttempts > X you lockout for some minutes.
This means you're locking the userid in question for some time, but not permanently. It also means you're updating the database for each login attempt (unless it is locked, of course), which may be causing other problems.
There is at least one whole country is NAT'ed in asia, so IP's cannot be used for anything.
In my eyes there are several possibilities, each having cons and pros:
Forcing secure passwords
Pro: Will prevent dictionary attacks
Con: Will also prevent popularity, since most users are not able to remember complex passwords, even if you explain to them, how to easy remember them. For example by remembering sentences: "I bought 1 Apple for 5 Cent in the Mall" leads to "Ib1Af5CitM".
Lockouts after several attempts
Pro: Will slow down automated tests
Con: It's easy to lock out users for third parties
Con: Making them persistent in a database can result in a lot of write processes in such huge services as Twitter or comparables.
Captchas
Pro: They prevent automated testing
Con: They are consuming computing time
Con: Will "slow down" the user experience
HUGE CON: They are NOT barrier-free
Simple knowledge checks
Pro: Will prevent automated testing
Con: "Simple" is in the eye of the beholder.
Con: Will "slow down" the user experience
Different login and username
Pro: This is one technic, that is hardly seen, but in my eyes a pretty good start to prevent brute force attacks.
Con: Depends on the users choice of the two names.
Use whole sentences as passwords
Pro: Increases the size of the searchable space of possibilities.
Pro: Are easier to remember for most users.
Con: Depend on the users choice.
As you can see, the "good" solutions all depend on the users choice, which again reveals the user as the weakest element of the chain.
Any other suggestions?
You could do what Google does. Which is after a certain number of trys they have a captacha show up. Than after a couple of times with the captacha you lock them out for a couple of minutes.
I tend to agree with most of the other comments:
Lock after X failed password attempts
Count failed attempts against username
Optionally use CAPTCHA (for example, attempts 1-2 are normal, attempts 3-5 are CAPTCHA'd, further attempts blocked for 15 minutes).
Optionally send an e-mail to the account owner to remove the block
What I did want to point out is that you should be very careful about forcing "strong" passwords, as this often means they'll just be written on a post-it on the desk/attached to the monitor. Also, some password policies lead to more predictable passwords. For example:
If the password cannot be any previous used password and must include a number, there's a good chance that it'll be any common password with a sequential number after it. If you have to change your password every 6 months, and a person has been there two years, chances are their password is something like password4.
Say you restrict it even more: must be at least 8 characters, cannot have any sequential letters, must have a letter, a number and a special character (this is a real password policy that many would consider secure). Trying to break into John Quincy Smith's account? Know he was born March 6th? There's a good chance his password is something like jqs0306! (or maybe jqs0306~).
Now, I'm not saying that letting your users have the password password is a good idea either, just don't kid yourself thinking that your forced "secure" passwords are secure.
To elaborate on the best practice:
What krosenvold said: log num_failed_logins and last_failed_time in the user table (except when the user is suspended), and once the number of failed logins reach a treshold, you suspend the user for 30 seconds or a minute. It is the best practice.
That method effectively eliminates single-account brute-force and dictionary attacks. However, it does not prevent an attacker from switching between user names - ie. keeping the password fixed and trying it with a large number of usernames. If your site has enough users, that kind of attack can be kept going for a long time before it runs out of unsuspended accounts to hit. Hopefully, he will be running this attack from a single IP (not likely though, as botnets are really becoming the tool of the trade these days) so you can detect that and block the IP, but if he is distributing the attack... well, that's another question (that I just posted here, so please check it out if you haven't).
One additional thing to remember about the original idea is that you should of course still try to let the legitimate user through, even while the account is being attacked and suspended -- that is, IF you can tell the real user and the bot apart.
And you CAN, in at least two ways.
If the user has a persistent login ("remember me") cookie, just let him pass through.
When you display the "I'm sorry, your account is suspended due to a large number of unsuccessful login attempts" message, include a link that says "secure backup login - HUMANS ONLY (bots: no lying)". Joke aside, when they click that link, give them a reCAPTCHA-authenticated login form that bypasses the account's suspend status. That way, IF they are human AND know the correct login+password (and are able to read CAPTCHAs), they will never be bothered by delays, and your site will be impervious to rapid-fire attacks.
Only drawback: some people (such as the vision-impaired) cannot read CAPTCHAs, and they MAY still be affected by annoying bot-produced delays IF they're not using the autologin feature.
What ISN'T a drawback: that the autologin cookie doesn't have a similar security measure built-in. Why isn't this a drawback, you ask? Because as long as you've implemented it wisely, the secure token (the password equivalent) in your login cookie is twice as many bits (heck, make that ten times as many bits!) as your password, so brute-forcing it is effectively a non-issue. But if you're really paranoid, set up a one-second delay on the autologin feature as well, just for good measure.
You should implement a cache in the application not associated with your backend database for this purpose.
First and foremost delaying only legitimate usernames causes you to "give up" en-mass your valid customer base which can in itself be a problem even if username is not a closely guarded secret.
Second depending on your application you can be a little smarter with an application specific delay countermeasures than you might want to be with storing the data in a DB.
Its resistant to high speed attempts that would leak a DOS condition into your backend db.
Finally it is acceptable to make some decisions based on IP... If you see single attempts from one IP chances are its an honest mistake vs multiple IPs from god knows how many systems you may want to take other precautions or notify the end user of shady activity.
Its true large proxy federations can have massive numbers of IP addresses reserved for their use but most do make a reasonable effort to maintain your source address for a period of time for legacy purposes as some sites have a habbit of tieing cookie data to IP.
Do like most banks do, lockout the username/account after X login failures. But I wouldn't be as strict as a bank in that you must call in to unlock your account. I would just make a temporary lock out of 1-5 minutes. Unless of course, the web application is as data sensitive as a bank. :)
This is an old post. However, I thought of putting my findings here so that it might help any future developer.
We need to prevent brute-force attack so that the attacker can not harvest the user name and password of a website login. In many systems, they have some open ended urls which does not require an authentication token or API key for authorization. Most of these APIs are critical. For example; Signup, Login and Forget Password APIs are often open (i.e. does not require a validation of the authentication token). We need to ensure that the services are not abused. As stated earlier, I am just putting my findings here while studying about how we can prevent a brute force attack efficiently.
Most of the common prevention techniques are already discussed in this post. I would like to add my concerns regarding account locking and IP address locking. I think locking accounts is a bad idea as a prevention technique. I am putting some points here to support my cause.
Account locking is bad
An attacker can cause a denial of service (DoS) by locking out large numbers of accounts.
Because you cannot lock out an account that does not exist, only valid account names will lock. An attacker could use this fact to harvest usernames from the site, depending on the error responses.
An attacker can cause a diversion by locking out many accounts and flooding the help desk with support calls.
An attacker can continuously lock out the same account, even seconds after an administrator unlocks it, effectively disabling the account.
Account lockout is ineffective against slow attacks that try only a few passwords every hour.
Account lockout is ineffective against attacks that try one password against a large list of usernames.
Account lockout is ineffective if the attacker is using a username/password combo list and guesses correctly on the first couple of attempts.
Powerful accounts such as administrator accounts often bypass lockout policy, but these are the most desirable accounts to attack. Some systems lock out administrator accounts only on network-based logins.
Even once you lock out an account, the attack may continue, consuming valuable human and computer resources.
Consider, for example, an auction site on which several bidders are fighting over the same item. If the auction web site enforced account lockouts, one bidder could simply lock the others' accounts in the last minute of the auction, preventing them from submitting any winning bids. An attacker could use the same technique to block critical financial transactions or e-mail communications.
IP address locking for a account is a bad idea too
Another solution is to lock out an IP address with multiple failed logins. The problem with this solution is that you could inadvertently block large groups of users by blocking a proxy server used by an ISP or large company. Another problem is that many tools utilize proxy lists and send only a few requests from each IP address before moving on to the next. Using widely available open proxy lists at websites such as http://tools.rosinstrument.com/proxy/, an attacker could easily circumvent any IP blocking mechanism. Because most sites do not block after just one failed password, an attacker can use two or three attempts per proxy. An attacker with a list of 1,000 proxies can attempt 2,000 or 3,000 passwords without being blocked. Nevertheless, despite this method's weaknesses, websites that experience high numbers of attacks, adult Web sites in particular, do choose to block proxy IP addresses.
My proposition
Not locking the account. Instead, we might consider adding intentional delay from server side in the login/signup attempts for consecutive wrong attempts.
Tracking user location based on IP address in login attempts, which is a common technique used by Google and Facebook. Google sends a OTP while Facebook provides other security challenges like detecting user's friends from the photos.
Google re-captcha for web application, SafetyNet for Android and proper mobile application attestation technique for iOS - in login or signup requests.
Device cookie
Building a API call monitoring system to detect unusual calls for a certain API endpoint.
Propositions Explained
Intentional delay in response
The password authentication delay significantly slows down the attacker, since the success of the attack is dependent on time. An easy solution is to inject random pauses when checking a password. Adding even a few seconds' pause will not bother most legitimate users as they log in to their accounts.
Note that although adding a delay could slow a single-threaded attack, it is less effective if the attacker sends multiple simultaneous authentication requests.
Security challenges
This technique can be described as adaptive security challenges based on the actions performed by the user in using the system earlier. In case of a new user, this technique might throw default security challenges.
We might consider putting in when we will throw security challenges? There are several points where we can.
When user is trying to login from a location where he was not located nearby before.
Wrong attempts on login.
What kind of security challenge user might face?
If user sets up the security questions, we might consider asking the user answers of those.
For the applications like Whatsapp, Viber etc. we might consider taking some random contact names from phonebook and ask to put the numbers of them or vice versa.
For transactional systems, we might consider asking the user about latest transactions and payments.
API monitoring panel
To build a monitoring panel for API calls.
Look for the conditions that could indicate a brute-force attack or other account abuse in the API monitoring panel.
Many failed logins from the same IP address.
Logins with multiple usernames from the same IP address.
Logins for a single account coming from many different IP addresses.
Excessive usage and bandwidth consumption from a single use.
Failed login attempts from alphabetically sequential usernames or passwords.
Logins with suspicious passwords hackers commonly use, such as ownsyou (ownzyou), washere (wazhere), zealots, hacksyou etc.
For internal system accounts we might consider allowing login only from certain IP addresses. If the account locking needs to be in place, instead of completely locking out an account, place it in a lockdown mode with limited capabilities.
Here are some good reads.
https://en.wikipedia.org/wiki/Brute-force_attack#Reverse_brute-force_attack
https://www.owasp.org/index.php/Blocking_Brute_Force_Attacks
http://www.computerweekly.com/answer/Techniques-for-preventing-a-brute-force-login-attack
I think you should log againt the username. This is the only constant (anything else can be spoofed). And yes it could lock out a legitimate user for a day. But if I must choose between an hacked account and a closed account (for a day) I definitely chose the lock.
By the way, after a third failed attempt (within a certain time) you can lock the account and send a release mail to the owner. The mail contains a link to unlock the account. This is a slight burden on the user but the cracker is blocked. And if even the mail account is hacked you could set a limit on the number of unlockings per day.
A lot of online message boards that I log into online give me 5 attempts at logging into an account, after those 5 attempts the account is locked for an hour or fifteen minutes. It may not be pretty, but this would certainly slow down a dictionary attack on one account. Now nothing is stopping a dictionary attack against multiple accounts at the same time. Ie try 5 times, switch to a different account, try another 5 times, then circle back. But it sure does slow down the attack.
The best defense against a dictionary attack is to make sure the passwords are not in a dictionary!!! Basically set up some sort of password policy that checks a dictionary against the letters and requires a number or symbol in the password. This is probably the best defense against a dictionary attack.
You could add some form of CAPTCHA test. But beware that most of them render access more difficult eye or earing impaired people. An interesting form of CAPTCHA is asking a question,
What is the sum of 2 and 2?
And if you record the last login failure, you can skip the CAPTCHA if it is old enough. Only do the CAPTCHA test if the last failure was during the last 10 minutes.
For .NET Environment
Dynamic IP Restrictions
The Dynamic IP Restrictions Extension for IIS provides IT Professionals and Hosters a configurable module that helps mitigate or block Denial of Service Attacks or cracking of passwords through Brute-force by temporarily blocking Internet Protocol (IP) addresses of HTTP clients who follow a pattern that could be conducive to one of such attacks. This module can be configured such that the analysis and blocking could be done at the Web Server or the Web Site level.
Reduce the chances of a Denial of Service attack by dynamically blocking requests from malicious IP addresses
Dynamic IP Restrictions for IIS allows you to reduce the probabilities of your Web Server being subject to a Denial of Service attack by inspecting the source IP of the requests and identifying patterns that could signal an attack. When an attack pattern is detected, the module will place the offending IP in a temporary deny list and will avoid responding to the requests for a predetermined amount of time.
Minimize the possibilities of Brute-force-cracking of the passwords of your Web Server
Dynamic IP Restrictions for IIS is able to detect requests patterns that indicate the passwords of the Web Server are attempted to be decoded. The module will place the offending IP on a list of servers that are denied access for a predetermined amount of time. In situations where the authentication is done against an Active Directory Services (ADS) the module is able to maintain the availability of the Web Server by avoiding having to issue authentication challenges to ADS.
Features
Seamless integration into IIS 7.0 Manager.
Dynamically blocking of requests from IP address based on either of the following criteria:
The number of concurrent requests.
The number of requests over a period of time.
Support for list of IPs that are allowed to bypass Dynamic IP Restriction filtering.
Blocking of requests can be configurable at the Web Site or Web Server level.
Configurable deny actions allows IT Administrators to specify what response would be returned to the client. The module support return status codes 403, 404 or closing the connection.
Support for IPv6 addresses.
Support for web servers behind a proxy or firewall that may modify the client IP address.
http://www.iis.net/download/DynamicIPRestrictions
Old post but let me post what I have in this the end 2016. Hope it still could help.
It's a simple way but I think it's powerful to prevent login attack. At least I always use it on every web of mine. We don't need CAPTCHA or any other third party plugins.
When user login for the first time. We create a session like
$_SESSION['loginFail'] = 10; // any number you prefer
If login success, then we will destroy it and let user login.
unset($_SESSION['loginFail']); // put it after create login session
But if user fail, as we usually sent error message to them, at the same time we reduce the session by 1 :
$_SESSION['loginFail']-- ; // reduce 1 for every error
and if user fail 10 times, then we will direct them to other website or any web pages.
if (!isset($_SESSION['loginFail'])) {
if ($_SESSION['login_fail'] < 1 ) {
header('Location:https://google.com/'); // or any web page
exit();
}
}
By this way, user can not open or go to our login page anymore, cause it has redirected to other website.
Users has to close the browser ( to destroy session loginFail that we created), open it 'again' to see our login page 'again'.
Is it helpful?
There are several aspects to be considered to prevent brute-force. consider given aspects.
Password Strenght
Force users to create a password to meet specific criteria
Password should contain at least one uppercase, lowercase, digit and symbol(special character).
Password should have a minimum length defined according to your criteria.
Password should not contain a user name or the public user id.
By creating the minimum password strength policy, brute-force will take time to guess the password. meanwhile, your app can identify such thing and migrate it.
reCaptcha
You can use reCaptcha to prevent bot scripts having brute-force function. It's fairly easy to implement the reCaptcha in web application. You can use Google reCaptcha. it has several flavors of reCaptcha like Invisible reCaptcha and reCaptcha v3.
Dynamic IP filtering Policy
You can dynamically identify the pattern of request and block the IP if the pattern matches the attack vector criteria. one of the most popular technique to filter the login attempts is Throttling. Read the Throttling Technique using php to know more. A good dynamic IP filtering policy also protects you from attacks like DoS and DDos. However, it doesn't help to prevent DRDos.
CSRF Prevention Mechanism
the csrf is known as cross-site request forgery. Means the other sites are submitting forms on your PHP script/Controller. Laravel has a pretty well-defined approach to prevent csrf. However, if you are not using such a framework, you have to design your own JWT based csrf prevention mechanism. If your site is CSRF Protected, then there is no chance to launch brute-force on any forms on your website. It's just like the main gate you closed.

Resources