Enterprise Java with Spring Boot

Hashing & Storing Passwords

Josh Long
Broadcom
Enterprise Java with Spring Boot

Lesson Description

The "Hashing & Storing Passwords" Lesson is part of the full, Enterprise Java with Spring Boot course featured in this preview video. Here's what you'd learn in this lesson:

Josh uses a PasswordEncoder to encode the plaintext password provided by the user and store it in the database. Any passwords using the deprecated SHA256 algorithm are migrated to bcrypt after the user successfully logs in.

Preview
Close

Transcript from the "Hashing & Storing Passwords" Lesson

[00:00:00]
>> Josh Long: And the reason it won't let me log in is because I got spring security in the class path. It's asking me for a username and password. What username and password? Well, by default, unless you specify something, you don't get one. Right? It used to be that you'd get like a default username and password.

[00:00:13]
I don't even get that. So the question is, what do I want to do? Well, I first have to answer the question of authentication. Who is making this request. I can do an in memory user system, e.g. in memory user Details manager, return new in memory using Details manager.

[00:00:28]
And I'm going to do a terrible thing that you should never ever do. I am going to create some memories, create some users in memory whose passcodes. I'll just store it in plain text here because I'm a terrible person. So user with J long hello, come back with j long roles user password is password.

[00:00:48]
Now where does that password come from? Well, I could just provide a plain text password, but you want to encode those passwords, they should never be stored in plain text. So what I'm going to do is I'm going to use a hierarchy in spring security called the password encoder, right?

[00:01:03]
And let me inject then that password encoder pw and I'll say pw dot encode pw. That's the. So the password, the raw encoded version of the password is this. It's VAR PW1, right? Encoded PW. I've passed that into the password here and I'm going to pass that into the user's thing.

[00:01:27]
Now this is in memory. Let's print out the encoded version of the password. So here we go. Start that up again. There you go. Actually it came out. So look at what has just happened here. It gave me the encrypted encoded version of the password. That's this bit.

[00:01:45]
But what's this bit? That's the prefix. That prefix tells us what encoding was used to encode that password. And the reason that we do this is because we want to be able to support migration. Right now bcrypt is widely considered to be the most secure encoding. So we use that by default.

[00:02:02]
But what happens tomorrow? What if the much vaunted quantum security threat apocalypse arises tomorrow? Right? What if they break bcrypt or something? Okay, so now we need a post quantum encoder. So spring security deploys one of those. Okay, great. But what about the old passwords, those old passwords?

[00:02:27]
What if somebody tries to log in and these are stored in the Database. You've got a database table full of users. Somebody tries to log in with those old passwords, right? With the passwords that are stored in the database using bcrypt. Spring security is going to go to the database and say hey, it's going to go to this in memory thing or to an actual database and say I've got an encoded version of this password in the database.

[00:02:48]
Never at rest, never stored in plain text, but it's encoded and I'm going to encode the current user's request, the current password that the challenge that was presented to the service. I'm going to encode that on this request. I'm encoding it with the post quantum encoder. But this old password is using Bcrypt.

[00:03:06]
So they're not going to work, right? So what I have to do is I have to encode, they're not going to match. That's how security works. I have an encoded password in the database. I have a non encoded password from the user. I encode that password from the user, turn it into the same encoding as is in the database and if they match then I allow access.

[00:03:24]
I need to know what encoding was. So we prefixed the passwords we with a string in this case bcrypt. Right? And the same is true for old. Like if you have old sha256 first of all don't. But second of all, if you do, we need to know that so we can use the old encoder to match that.

[00:03:39]
Okay, so by default we encode passwords. That's what this password encoder factory is doing. It's a delegating password encoder. If you look at this, it actually has a bunch of different encoders that get put in a map. These are all the prefixes that that tell us what the nature of the encoding is for each of the passwords.

[00:03:57]
So if we see that you're trying to authenticate using a password in a database using Scrypt, then we'll use the script encoder to try and match it, right? To try and to validate it. Okay, so let's see if that works. We should be able to get to hello and see the current authenticated user.

[00:04:12]
Because we've only got the one user, right? Let's actually create and the user. By the way, I'm doing it in memory. I've got one role. Okay, paste that in. Paste this. I'm going to add Spring security lead Rob Winch, with whom I trust my life and my data implicitly.

[00:04:31]
Restart that okay, so I'm going to go to localhost880. Hello again. Jlongpw and it says hello jlong. So clearly it's worked. I'm authenticated. I'm able to hit the endpoint. Fine. But like I said, that's in memory. It's not really what normally people will do, right. They're going to store stuff in a database.

[00:04:54]
So let's switch this out and actually, you know, to keep the example consistent, let's imagine that I had done Josh and Rob. Okay, that's the old in memory 1. Let's switch to a database being JDBC User Details Manager. Okay, I need a data source turn new jdbc. Voila.

[00:05:15]
Okay, so that's going to expect some schema to be in place. Now my question is, did I in my infinite wisdom, did I put that in the front end? Masters git repository open security auth. Yes. Okay, I'm going to copy and paste that schema here to my downloads directory.

[00:05:47]
Open. Copy and paste that source main resources paste. Okay, so let's look at that schema here. I've got some users. Josh, Rob, an accountant. I've got some roles I'm adding there. Role user. Role user for Josh and Rob. And Rob, because he's the goat, he also gets admin privileges.

[00:06:10]
That is going to go into a schema that I have here. Create table authorities, create table users and add some foreign keys and indexes and all that. This schema is in the Spring Security jar. There's a generic version that you can find in the Spring Security jar itself or in the source code for Spring Security, the project.

[00:06:28]
It's on GitHub, but I'm going to include this. This is in the git repository already. You can find the code there. And this is for postgres. I'm using postgres. I had to tweak it in some mysterious ways that I don't remember, but this definitely works. So you can use this.

[00:06:40]
Okay, so I'm going to. Everything else is the same. I'm just swapping out the bean that I'm using. So instead of using in memory User Details Manager, I'm using a JDBC User Details manager. So far so good. So we restart that. I have to tell it to load the schema, don't I?

[00:06:58]
I forgot to do that. So go over here. Sequel init always. Okay, same as always. Click on this little button. Click on that button. Click on Apply. Click on. Ok. Click on this, click on that, click on that, click on that. There we go. There's our users and our authorities.

[00:07:17]
Okay. And you can see that these are using the old password encoder SHA256. So I went out of my way to encode some passwords in the wrong format. This is no longer secure. You know, this has been dead from a security perspective for a decade. Do not use SHA256.

[00:07:35]
So this is not secure. But I have passwords in the database. Well, of course, unless I get out a lot of machines, I can't reverse these. It can be done. I just don't want to have to do that. So I want to migrate these passwords. Let's first make sure that I can log in.

[00:07:48]
Okay, let's just do that. So Josh pw. Okay, great. Okay, let me go to a new incognito window login. Rob pw wait. Sorry. Hello. There you go. Okay, so it's clearly, it's able to log me in and out with that in memory JDBC thing. The problem is I've got these old passwords.

[00:08:15]
I do not want these old passwords laying around in SHA 256. If this database, if somebody hacked this database and this data went out, somebody could ultimately reverse engineer that. It wouldn't take a lot of computing power. So we want to make sure that never happens. So we want to migrate their passwords, but obviously we can't easily migrate.

[00:08:33]
It would take computing power. I don't want to do that. Especially with bcrypt, I couldn't do that, not easily. So rather than me trying to brute force my own users passwords, the most sensible thing is to as they log in once they've presented a challenge, once they presented the credential to respond to the challenge that we're forcing them to authenticate.

[00:08:52]
Once they've done that, when the value is in memory on login and we can see that, and once we've confirmed that it authenticates correctly, migrate them seamlessly, you write out the value to the database to update the value to be bcrypt. So let's do that. I'm going to change my code here to use bcrypt.

[00:09:17]
Where's my application here? Okay, go over here. Comment that out, go down there. I'm going to create a new bean user details password service. Okay. And in order for this to work, this seamless migration is not automatic. We want you to do it yourself because we don't know if we might break anything.

[00:09:40]
So here's this service gets involved when you authenticate and you get a chance to, you get a Chance. Once their authentication is successful, you get a pointer to the current user and to the new password, the unencoded password that the user has entered that we know is valid because it matched.

[00:09:59]
So now your job is to, with the injected JDBC User Details manager, create the new user with the new data. So user with user details. User. Right. Not user details. User. Okay with user details. What's wrong with that password? New password.build. it's this. Okay. Updated. Okay. So I've created, I've cloned everything from the existing user details, except the only thing I've changed is I've specified a new password.

[00:10:35]
Yeah. And that'll implicitly migrate it to the new encoder. Right. And the reason that that'll happen is because I'm going to save it. So I use the user details manager and I say update. User. Updated. Updated. Okay. And then I can return updated. Let's try that. Now I'm going to restart this code.

[00:11:01]
So now I go to hello, new incognito window. No Josh, no Rob. So let's make sure we're on the same page here, though. Users still sha256. Right. PW and this one has been decrypted. It got migrated in place. Passwords are terrible. You should not use passwords. People forget to change them.

[00:11:26]
They become archaic. They use the same one in multiple systems. Not everybody's going to use a password manager, but if you're going to do passwords, do it right. Make sure it's encoded, make sure you have ways to seamlessly migrate forward. But they are terrible, really. The goal of a good security system is to avoid passwords at all.

[00:11:42]
They're not a good idea. And there's actually, you know, there's actually government regulations around how people should manage password passwords, the lifetime of passwords and so on. And this advice changes. Do you know that it's actually kind of counter indicated, contraindicated that you should force users to migrate their password every month or whatever to change their password.

[00:11:59]
That practice of you need to change your password every quarter. That's not actually good security practice anymore. There are government standards that talk about this stuff, Right. I didn't know that. I thought that was like. It still happens to me all the time. I'm forced to like migrate my passwords.

[00:12:11]
In certain cases it's a bad idea. So I want to avoid passwords. But if you're going to do it, do it like this. Okay? Do it so that it's secure.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now