Handling expiration & validation of 2FA codes [closed] - security

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am currently planning a 2FA implementation to require users to provide a code via SMS for some actions, like a login. I will also use tools like Google Authenticator, but I do not want the users to force to download the app, thats why I need to send the codes via SMS (or potentially email) as well.
My plan so far is:
User wants to login and requests a code
Backend generates a numeric code, stores it hashed in DB and returns the ID (or selector) of the database entry to the frontend
Frontend displays a code-input field next to the users email & password
Code is sent to the user via SMS / email
User has now 5 Minutes to send the selector + code + email + password to the backend where all those get validated
2 Questions about this:
1) Handling expiration of code
My first idea was to store the code only hashed like a password in the database, but I would have to implement the 5 minute expiration myself. Of course I could add another column with a timestamp to check the expiration, but I would rather go with something more secure.
Now I am thinking about to store the code inside the claims object of a json web token in the database and set the expiration of this token to 5 minutes. So after the 5 minutes are over, parsing the web token to compare it with the code the user has sent, fails. This would allow me in case of an attack scenario to just change the secret of the web tokens and all existing codes would be invalid instantly.
Is this a good approach? Or do you guys see any problems in this, or are there maybe better ways of handling it? Or is there maybe a library for hashing passwords with an expiration date as well?
2) Validation & handling brute force attacks
As I only want to send a 6 or max 8 digit numeric code to the user, I will have to implement some sort of protection against brute force attacks (lets assume that an attacker knows the email & password of the user).
What I want to do:
If an invalid code was sent once, increase the failed tries of that specific code db entry += 1
If the code exceeds 3 failed attempts, invalidate the code in the database and ask the user to request a new code
When a user requests a new code, have him wait 1 minute before he can request a new code, store the date of the last failed attempt as a timestamp in the users db entry as well as the 1 minute delay
If the third code fails, store the new timestamp and double the delay to 2 minutes
... and so on. After 3 failed codes a JS Challenge (Google Recaptcha) will be required as well.
After 5 retries I would lock the account and wait for the user to contact us.
I this a secure approach to handle the validation of the codes?

I think you're overdoing th security of your six-digit verification codes by using JWTs.
No matter how you manage them, you must invalidate them when they expire or when they're used. A good way to do that is to give each code a row in a table including the expiration timestamp. Then DELETE the row for the code when the user presents it. Whenever you look up those codes add WHERE expires > NOW() to the query. And routinely DELETE expired rows.
Resisting brute force attacks is straightforward. By the time you're ready to send your user a code, you have already validated their password so you know who they pretend to be. So just keep track of that user's attempts to guess the code. As you suggested, give them three tries. Then make them request another code. If they rerequest more than five codes in a calendar day, lock them out until the next calendar day.
This scheme, by the way, is useful for generating all kinds of nonces. (Numbers used once.) Nonces come in handy for many purposes like password resets by email.

Related

Why do we need JWT tokens for security despite still able to change own`s [duplicate]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I've been searching how to make a public http request secure and all the answers are to use a token like JWT.
But from what I understand, the reason for using this token. Isn't this to prevent someone from trying to modify someone else's data other than your own?
Then user can still manipulate his own data using his own tokens. Because when you first connect to the app, you will get a token from the server.
That person can modify his or her data at any time. Wouldn't he be able to modify the game points he has at any time? (I actually saw an answer in another answer (which said to make that http call only available once after the game is over))
but if he knows the jwt token and http request url then he still can modify right??
Are JWT tokens used in the worst case to keep someone else's data from being touched?
The JWT token is just used identify the user making API request and checking whether the user is authorized to make that request. When you decode a JWT (Firebase Auth's JWT for this example), you can read user's UID and custom claims, etc.
Passing user ID directly in API requests is not a good idea because they are usually public (e.g. your Stackoverflow ID is 18516895) and easy to guess. So I can just try passing some random numbers/string and might be able to make requests on behalf of someone else. So JWTs are mostly used for Authorization and Information Exchange.
Also checkout: Introduction to JSON Web Tokens
But suddenly I want to raise my stack overflow score. Then just checking the token is not enough for server I guess. right? How do you prevent in this case?
Allowing users to update their score doesn't seem to be a good idea. Instead the score should be done totally on back-end and can be triggered by any action such as user winning the game.
Take Stackoverflow for example, only the person who has asked the question can mark any of the answers as accepted. This is authorization. No one else is allowed to do so. After an answer is accepted, the system updated answerer's score (reputation), so there is no API request that is made from client side to increase score.
The flow could be like:
Questioner accepts an answer
Verify JWT, marked as accepted if owner of question
Increase score (reputation) of answerer
Adding to another case of single player game Tetris where the user directly needs to update server for a win and earn points as discussed in comments, it might be best to send every move to server and run all game win logic on backend instead of checking for win on client and letting users hit a /win API over and over again. If the game is completed, then credit points to user if won.

Nodejs: How do you differentiate between users?

I am new to backend. Only way i can think of is this:
at visit if doesn't have cookie then do next step
generate unique id and then set it as cookie
then upon every request check if that id is present in database and if not go to step 1.
if it's present then fetch data under that id and respond as needed.
Now is it safe?, Is it logical. What does actually happen.
Scenario to use in:
This is meant for not logged in users. Basically, users visit my site, click something that takes time.. so user is redirected to a page with waiting gif all the while using ajax (long polling) server is requested for results. Now to differentiate between requests from multiple users i am thinking this will work. It's important because data i'm going to be sending back is going to be private from 3rd party.
You have to decide up front if you want a:
Temporary session for a given browser that will only work for that user in one specific browser and may be reset at any time
or
A longer term session associated with a particular user that they user can use any time and from any browser.
The first can be done with a server or client generated cookie that is any globally unique value. You can then use that id as a key into your database to get the user's server-side settings/data on any given request. In node.js, there are a number of session related NPM modules that will handle the generation of a sessionID for you automatically. The problem with this first method is that it relies on the preservation of a cookie value in the user's browser. Not only can cookies be temporal (they can be cleared), but they are only set in one specific browser.
If you're only planning on using it for the duration of one session, then this first method should work just fine. It is common to use a time value (e.g. Date.now()) combined with a random number for a unique id. Since no two requests can be processed in the same ms, this guarantees a unique id value. Add the random number to make it not be predictable. Other NPM session modules offer further features such as an encryption key, etc...
The second method requires some sort of identifier that the user must enter in order to know which user it is (often an email address). If you don't want other people to be able to impersonate a user by only knowing their user id, then you also need to require a password. This essentially requires a sign-up process on your site where the user ends up with a userID and password that they use to login to your site.
It is not uncommon to see the first method used for short term storage on behalf of the user. For example, a shopping cart on a site that you are not registered for.
The second method is used by all the sites that have a user login.

How maliciously made multiple user registrations are managed on a real world website? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've notoced lots of websites allow users to register by simply asking their email and password [aside all the other information like name, username, genre etc.]. And the users don't have to do email verification as they register, they simply have a reminder that they should verify their email, but otherwise they can use the website normally. This is very good for UX, since the user can immediately start using a website and not wasting time to do email verifications etc. before he knows whether he will keep using this website or not.
So the question I wanted to ask is the following:
Suppose a malicious user writes a program that will keep registering users with valid usernames and valid(syntactically) emails.
This will eventually cause lost of trouble if not correctly managed:
the database will eventually run out of ids for users
This will create lots of records, thus eating up space
More user records, means more lookup time
So, I'm really curious how all this is managed, if at all.
NOTE: most of websites I'm talking about, do not use CAPTCHA(bad for UX), so they manage the issue in some other way, again, if at all.but neither the solution is to delete the record if the user hasn't confirmed his/her email in a time term. For suppose user looses Internet connection[, or forgets, or anything else] the last day he has to verify email. So the user will loose his/her account and just forget about that website. So this is not a solution. not sure about IP limitations. But suppose that is an Internet cafe and users keep registering. And there are dynamic IPs these days. Is limiting the registration to some amount of time a solution? But how do I know when the last registration occurred if the IP keeps changing. So how is this issue solved?
This is not really an SO problem. This site is more focused on solving issues with actual code rather than ways to solve a generalise problem.
That said, the current patterns seem to be...
Require more information. By having more information, you can de duplicate accounts. That said, in your scenario repeated accounts with the same email address should be easily consolidated. This doesn't prevent bots from registering many accounts with different addresses, but adding more requirements, such as address and phone number make it increasingly differcult to match data sets to your validation.
Validate via email. Contrary to what you suggest, this is still quite common and a good means to weed out genuine users with interest in the site from the chaff.
The other option is a federated authentication service such as Facebook, Twitter, Google+. These provide the UX you seek, but without it being your problem to validate.
From your comments that these changes aren't an option...
Your other option is to look at something server side. This will be along the lines of blocking by IP address. The problem I'd have with this is that the user is unaware, at least with the other options presented the user isn't going to get denied based upon something that happens backend. These measures can still be easily circumvented. An IP block can only be implemented for a short period of time, so the rogue registrations just need to delay long enough or more likely flip between different IP addresses.

authenticating a client which sends same data all the time, no user accounts

I have a client that records button clicks, and i want to send how many times a button has been clicked every 20 seconds in an http message, and i want to avoid potential hackers who will send fake messages to the client. There are no user accounts, the client simply sends the number of clicks with no sessions or logins or anything like that.
I thought about sending a hash of the current time and date + some password and send the time and date unhashes for the server to authenticate. but how am going to implement it? I mean a hacker could be sending the same time and date and password all the time, so should i additionally check whether the time and date is within the last 5 minutes or something of that sort? Any tips?
It probably have been asked here before as it sounds like a very "common" thing, but i was sort of unsure about the relevant terminology regarding this issue and couldn't find an answer
what you are trying to do is security by obscurity. --> hide your algorithm so noone will be able to reproduce the result.
basically a very bad idea. use existing authentification algorithms, they are prooved and better than all the things you come ever up with Possibility: el Gamal / DSA or RSA
You combine the following data and sign it with RSA:
- the message
- the actual time
with the public RSA key of the sender the receiver can check if the signature is correct.
you remember the dates of valid messages (if a message with a date which got already processed comes again it has to be an intercepted and resent message from a "hacker" so you dont process it even when the signature is correct)

Review my design: Password resetting facility for web site

When someone has lost a password, they click on the lost or forgotten password link.
They will need to enter their email address, then answer their own secret question
if the secret question is correct, an email will be sent to them with a link that expires after 24hrs.
As the email is sent, a record is entered in a database table holding this information:
- the email of the person who needs to reset the password
- the hour which the resetting of the password will expire
- the hour which the request to rest the password was submitted.
The sent link will lead the user to a form that allows them to enter their new password.
In this form they will need to enter their email address and their password X2.
When they click on submit, a check is made against db to ensure that the email is valid (one that the password is being reset) and has not yet expired (by comparing the two dates to see if the expiry time has passed, which is 24 hrs)
If the email is valid, and has not yet expired, and the two passwords match & meet the minimum req, then the new password is applied.
A confirmation message is given on success.
Q1. Is this a good model for password recovery?
Q2. How can I make sure that the link that is sent to the user's address is unique? In that no one will get the same link? So that nobody could just go to the password reset page and try different emails, rather have each account that needs to be reset have their own unique URL that work for that account only.
Regarding Q2:
I was thinking that when the user requests to have their password reset, a random unique id is generated and stored in the same record that expires after 24hrs. This random unique id's column could be called "rid"
The link in the email that will be sent to the user will end with ?rid=xxxxxxxxxxxxx
When the user clicks on submit in the page that resets the password, the "rid" at the top of the page is used to get the corresponding email address from the db, to compare it with the email address in the form. Doing this can ensure that each password reset case will have its own unique URL that no other account can use to reset its password.
Is this a viable solution?
Any contributions or suggestions will be appreciated.
Optimally:
Log me in through OpenID. Less coding complexity, less clicking, less typing, less time wasted.
Done. Question is moot. No need to worry any more, someone else already solved this problem.
There are a billion sites implementing a billion authentication schemes and in 99.999% of the cases it's unnecessary. Why should I as a user trust you as a developer to not store my password in plain-text or leak it or get hacked yourself? Few people use different passwords for every site...
If that's not possible, then make is as hassle-free as possible:
I click a "forgot password?" link. This automatically sends a mail if I've entered an e-mail already (e.g. after a failed log-in attempt). If I haven't entered one, simply hide the password field and tell me to do so. Don't reload or forward me to a different page.
I get a link to with some key (for example https://site.com/account/reset?key=a890ea8219175f890b7c123ee74a22). Some unique hash that is tied to my account and expires in so and so many hours. Use SSL if at all possible.
I click the link and you fetch my account details by the key, making sure it is valid and hasn't expired. I type in my new password twice. I already know what my e-mail address is, and you already know what my e-mail address is, and any would-be hacker would also know what my e-mail was, so don't ask me to type it in. Having the link last a whole day is overkill. Time it out in an hour or less.
I hate the security question. Don't ask me that. It's basically just a second password that's deliberately made less secure so you'll always remember it. I don't have frequent flier miles, I don't know my mother's maiden name, etc. Stop it. I know it's there to keep out strangers who might have hacked your e-mail, but unless you're PayPal I think it's just over-engineering.
When you have confirmed that the passwords match and they are acceptable, update the database (store only a salted hash of my password, not the password itself!) and log me in immediately. Do not redirect me to the log-in page where I have to retype information I've already given you several times now (and even though you already know it's me and trust me enough to change my own password). That is so annoying. Users are impatient.
I also dislike randomly generated passwords based on the following:
Usually I just copy-paste the password from the mail anyway. Copy-pasting a password is something you never want the user to do.
I have to go change the password manually, which means messing around in the user control panel or account settings or whatever. I am getting impatient! You could pup up with a "change your password" the minute I log in with a one-time password, but this means added code complexity. You now need to add a flag for this, add another redirect, handle the case where a user times out on entering a new password, etc.
Because I am only human, and humans have ADHD, I usually forget to do the above and I end up with a crap password I have to find and copy from my e-mail the next time I need to log in as well. My fault, but I'll still blame your site for it. ;-)
The randomly generated password solution is also implying the mentality that you'll always use a password-based solution, when link-based authentication seems to be the future (OpenID, etc.) in usability and security (I don't want a hundred small sites to know my login-details!).
Update to respond to comment:
Why the hash should be enough: if a hacker can guess the full 128+ bits (say) of your generated hash (and within an hour), then why wouldn't he or she also be able to guess the e-mail? I know that it "feels" a lot more secure to ask for the e-mail and/or a security question as well, but if you think about it, e-mails are usually very predictable and uniform, with low entropy rate. I doubt they can be counted on as containing more than 50 bits of information. (Probably a lot less.) I bet you I'd sooner guess your e-mail than I would a 50-bit random integer. But if it is a real worry, all you need to do is add more bits to the hash. 256 bits or so ought to do it for overkill mode -- SHA256(salt, email, old pw hash, time stamp, maybe some bytes from /dev/urandom) or similar... If a hacker can predict that, there's not much you can do really. Obviously he has control of The Matrix and could just project his mind onto the magnetic platters inside your hard drives if he wanted to.
Still Pro-OpenID: any new site I visit that demand I create a user ought to be very convincing as to why they want to know my (throwaway) password and what they offer me in security that OpenID or Google/Facebook/etc. does not -- or why they don't trust Google/Facebook/etc. Nobody (that I know) goes around remembering 30 different passwords. Usually people reuse them, so if these third party site creators wanted to, it'd be really easy for them to scam their users. If I registered at your site with my usual info, you could immediately take over my Last.FM and Reddit accounts if you wanted to, as well as probably a dozen sites I've used a couple of times and forgotten about. In fact, in these modern times, I kinda expect sites to either be ignorant or have malicious intent if they want details they strictly do not need, so that's why I call it a throwaway password -- with every sign-up it feels like I am saying "here, have my Reddit account, it's the same L/P as I'll be using for your site (otherwise I'd just forget). It's fine, I'm not particularly attached to it any way." Of course, Google could actually take over everything of my online self if they wanted to, but for now I'll trust Google more than you (no offense!).
First, I would suggest you treat a password-reset like a secure business transaction. SSL on, and a single request is independent of other requests for the same account. Generate a random, non-reusable transaction ID and associate it with THIS SINGLE REQUEST for a password-reset. Then, in the email you send to them, embed the transaction ID with the URL:
http://www.yoursite.com/passwordreset/?id=e3dXY81fr98c6v1
This so-called password-reset transaction should be associated with the account and have the metadata associated with a password-reset such as date of request and expiration date. The account itself should only know that there is/are pending password reset(s) associated with it.
Also, when a user asks to reset their password, forget the secret question - it's far more secure to send them an email that you should ALREADY have on file. (If you don't, then start collecting them!) - better yet, use their email address as their username.
When the user enters a new password from that transaction ID URL, you are trusting that it is the person you think it is. To ensure this, you can simply ask them to re-enter their username (which you already confirmed you are doing).
Q1. IMHO, there is a flaw. Why are you asking the user to enter a new password? I would rather generate a new random password and send it to him. After receiving it, the user can login using this randomly generated password, then change it in his/her profile.
I suggest the following system, used on the most websites:
The user enters a mail address in the "Password reset" form.
The mail is validated (ie. is there a user with this mail address in the database?)
The new password is randomly generated and sent by mail, then salted/hashed and saved to the database.
The user logins.
It's easy and common, so the users will not be lost.
Now, you can increase security (decrease abuse) by:
Setting password reset ratio. Once the form is submitted, the IP address and submitted data is remembered: now, for a few minutes, nobody from the same IP address will be able to reset a password anymore.
A newly generated password does not replace the old one: instead, both can be used. Imagine somebody resets a password of another user. This user must still be able to login with the old password, if he/she has not read or received the mail with the new password.
By the way, but it's just my personal opinion, do not provide secret question/answer feature, unless it is required. I have too much pain remember what I answered where, so I would probably have more risk to forget the answer than the password.

Resources