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