Full Web Apps with FastAPI Transcripts
Chapter: Storing data with SQLAlchemy
Lecture: Storing the password securely
0:00 The final thing to get our SQLAlchemy stuff really working 100% has to do with storing passwords.
0:07 Now storing passwords is tricky. You wanna make sure you get it right and doing it yourself is probably not the right way.
0:13 So over here, let's check out our TODO's that are pending, says set the proper password. What that really meant is take the plain text passwords
0:22 and set the hashed password to a hashed version. If we just do an MD5 hash, there's these look up tables. This hash equals this word,
0:31 this hash equals this word. We can't do it that way. Also, we wanna make it computationally expensive to guess if for some reason our
0:37 database got stolen and somebody got ahold of those hashed passwords, we don't wanna just hash it once,
0:43 because then you could just guess a bunch of things. So there's a lot of different things,
0:46 like bringing salt that is arbitrary text into, mix it in with the word but also hash folding or password folding, where you hash it,
0:54 and then you take that result and you hash it again, you take that result and hash it again a 100,000 times so that it's really computationally
1:01 expensive to take a guess at a given word, much more so than a single hash.
1:07 So what we're gonna do is we're gonna use this package that makes it much easier
1:10 called Passlib. It does all those things with a variety of different cryptographic algorithms
1:14 really, really easily. So what we're gonna do is we're just gonna go and add passlib and let it do all the hard work for us and get
1:22 things right. So passlib another one to install and it's not misspelled. Now up here at the top, I need to import something from passlib.
1:32 So I'll say from passlib, and I want to import it as a certain thing so if we change the algorithm, we can actually change the underlying algorithm,
1:41 we don't have to change the code just because the name of the algorithm changes. So what I'm gonna write is from passlib.handlers.sha2_crypt
1:48 and here on import sha512_crypt Not like that though, but as crypto. That way, if we decide to use bcrypt or a different algorithm,
2:00 it'll still just be one of these providers, one of these handlers called crypto. Okay, so that allows us little flexibility.
2:07 And down here, this is incredibly easy to use. All we have to do is go to crypto and say encrypt.
2:14 We give it the password, and it also takes a bunch of arguments. See if it'll have documentation inside. Oh, it looks like it was renamed to hash.
2:23 Okay, let's call hash, then. Fine. And the secret is password. Does it say what its keyword arguments are? I know which one I want,
2:30 but I'm not sure, I was hoping for documentation. So what we could do is we could come over and we could say round equals let's say, 172,434.
2:42 So I talked about that folding and do a hash, and you do the hash of the hash, the hash of the hash of the hash. This will do that iteratively
2:49 172,434 times making it computationally expensive. If you wanted to be, take longer, you make it higher. You wanna make it a little bit quicker,
2:57 I'm guessing This is about 1/10 of a second, I'm not 100% sure. Let's go and do this and register a new user and see what gets into our database.
3:05 So register, this'll be Sarah Jones. this'll be firstname.lastname@example.org. She loves the password "abaaaa" and who knows how old she is.
3:16 We hit this, we get our account and let's go to our database and have a quick look. She's at the bottom and now check this out.
3:27 Copy this and I'll just put over this query page here so you can see it Look how giant, enormous that is for, like, four a's and a b.
3:36 This is all sorts of craziness. So it tells you the algorithm that was used, the rounds here, ups don't move that around for me.
3:43 The rounds that were used, the number of iterations and then a combination of the
3:48 encrypted result, along with hash that was randomly created for the salt that was randomly created for it, and so on.
3:54 So this is way more secure than storing plain text. Even better than just hashing it once, right? So it has randomized, per user salt,
4:02 plus the iteration. Really, really nice and how hard was it? It literally couldn't be easier.
4:09 crypto.hash(password). Now, what is not so easy is how do I verify that? How do I verify that that is actually the password.
4:18 Well, what we're gonna do is I'm gonna come over here, we don't have to remember the rounds, it's stored in the result.
4:25 But when we log in, we need to say we're gonna get the password that they provided and we wanna compare that.
4:32 So we're gonna come over here and say crypto.verify. It doesn't say "decrypt" because you cannot decrypt the hash.
4:39 But you can look at all the pieces and hash it again and say, Did the outcome match? So here what we're gonna pass over is we're gonna pass over
4:46 the secret, which is the plain text password And then we're gonna pass over the hash, and that is what we stored on the user object,
4:56 the hash_password. And if it's not verified, We're gonna say no, get out of here. Otherwise it will return the user. So look at that, to use passlib,
5:05 literally that line and that line and we're covering so many good practices around storing passwords, incredible. Let's go try to create,
5:13 uh, let's go try to log in, as our other user. Hope I remember the password, right? It was email@example.com, I think it was "abaaa"
5:22 We'll find out if it doesn't work. No, password's wrong. Let's register a new account. There's no reset. Uh, Sarah Jones2
5:29 firstname.lastname@example.org and we'll set a decent password and register. Now let's log out and see if she can log in again.
5:37 So come over here. Use that same email address. Boom, we're logged in. That's awesome. If I were to put in an invalid password, something else, nope,
5:50 doesn't exist. It doesn't let us log in. So really, really fantastic. This passlib, how easy it makes storing passwords and doing user management
5:58 correctly. FastAPI has other ways of authenticating users and doing authentication. We're not gonna go into it in this course,
6:05 right? Use just this user name and password integration here. But if you wanted to do like Federated Identity or OAuth or stuff like that,
6:11 the framework does support it, but it's sort of beyond the scope of what we're
6:15 doing here to get deep into user management and different types of authentication. Pretty awesome. I'm super, super pleased
6:22 the way this came out, that is the way to do things. And that's a really nice way to verify that
6:29 they are logged in correctly. You saw in the database, go back to our users. Now we'll have a couple examples.
6:34 You look at these two. The number is the same there, but then after that, it's just all randomness, and it's not anywhere near the same thing.
6:43 Super super cool way to store this users in our database.