Implementing Secure Password Verification in User Login
00:00 Because we don't have logout implemented yet, we are going to have to go to our application cookies and clear this out. So then if we refresh, we are now logged out. We're going to implement that later, don't worry. And so now I want to go to my login route right here. And right here,
00:16 we've got our action, we are currently getting the user, but we're not comparing their password. So we actually do need to get the password here. So we're going to say password and select and hash true. So that way we get the password hash. But now we've just done something a little bit
00:33 dangerous. And that is this user now includes the password hash. And we're returning that password hash. Remember, we don't want to send that password hash to the client. So what we're going to do is rename this to user and password. And in this case, if there is no user and password,
00:50 or they don't have a password, then we can't really compare it anyway. So if there's no password, then we're going to have this issue. And then down here, instead of returning the entire user and password object, we're going to just return another object that has an ID
01:05 user and password dot ID, that'll be the user's ID that way we don't return the user and along with their password, we're just going to return the user with their ID. And then we're going to say be crypt bring that in from our server util. And we're going to await this. And we say compare
01:24 the password that we get from the form submission, the form that they submitted with the password, and compare that with the hash that we have in the database. Now again, this hash also has the salt, so we don't have to worry about that be crypt takes care of all that for us. And now we can say
01:39 is valid. If that returns true, or if it returns false, if it's not valid, then we need to do something very similar to this. So that's what we're going to do right there. We're not going to give the user any more information, we're not going to say, oh, yeah, your username was correct,
01:55 but your password was wrong, like that typically is not a great idea. Because it allows very easy access to it does this username exist. Now for an app like this one, that's actually really easy to determine, because you can literally just go to that user page, because all of our users
02:12 are public. And that like that would apply also to like any social media site, or even when you're signing up, we also tell you whether the user's name is unique. So that actually doesn't matter a lot to our application, whether users can be determined by their username. But for other applications, that is quite important. And so that's why we're going to follow suit in here.
02:32 Now, this actually also opens us up to what's called a timing attack, which basically allows a an attacker to say, okay, I'm going to hit this with a username that I know exists. And this is how long it takes. And now I'm going to change the username. And if the user does exist
02:53 by that username, then they can actually time how long the response takes. And if the response takes extra long, then they know, oh, okay, so we made it past this first check. And we're now going into comparing the password. So I know that that username exists. So timing attacks are not awesome.
03:09 And there are ways to get around them, which are outside of the scope of this workshop. But basically, the idea is you just make make it so that your request for comparing the user passwords and validating the submission is just totally random in how long it takes. And it doesn't have
03:26 to be that random. But or that doesn't have to take that long. But having some sort of randomness there will kind of help prevent against timing attacks. But again, we're not going to be implementing that here. And in many cases, you don't really need to worry about it.
03:41 But I bring this up also because bcrypt compare part of the security of the bcrypt hashing algorithm is that it is intentionally slow. And so it's hard to brute force to determine the password. And then also, we did rate limiting in a previous exercise as well. So brute forcing the passwords is
03:59 not really going to be an issue for us either. Okay, so let's make sure that this works, though we've gone through all of this work, let's just make sure that this will function. So if I go Cody and Cody loves you, I can log in as Cody. So this does in fact work. The quick review of this
04:16 is we had to grab the password hash from the database. And then we double check that the user does in fact have a password. And if they don't, then we send back this response. Now right now, all of our users do have passwords. But in the future, there will actually be users that don't
04:31 have passwords when we do third party authentication. And then we compare the password that they provided. So this is the actual text that they typed with the hash that we have stored in the database. And if it's not valid, then we'll send them back in error. And then otherwise,
04:49 we're all good to go. So we'll send back all the data they sent to us, plus a user that just has the ID. And we made certain to not include the user hash as well. And that is actually comparing the user's password. So now users cannot log in as just anybody,
05:06 they have to know what the password is. So great job.