WEBVTT 0 00:00.730 --> 00:01.080 All right. 1 00:01.110 --> 00:08.280 So now that we've seen what some of the vulnerabilities might be for hashed passwords it's time to level 2 00:08.280 --> 00:16.620 up and learn about a way that we can prevent these types of dictionary attacks or hash table cracks. 3 00:16.890 --> 00:21.060 And in order to do that we have to learn about salting. 4 00:21.180 --> 00:23.430 Now what exactly is salting? 5 00:23.430 --> 00:26.370 Well, we already know what hashing is. 6 00:26.420 --> 00:33.420 It's when we take a password, we run it through a hash function and we end up with a hash that we store 7 00:33.450 --> 00:34.980 on our database. 8 00:34.980 --> 00:41.340 And as we saw in the last lesson, passwords that are generated by humans are extremely insecure. 9 00:41.430 --> 00:47.190 They tend to be very short and they tend to be dictionary words that are extremely easy to look up and 10 00:47.190 --> 00:52.850 create a hash table for. Now salting takes the hashing a little bit further. 11 00:53.010 --> 01:01.470 In addition to the password, we also generate a random set of characters and those characters along with 12 01:01.470 --> 01:06.590 the user's password gets combined and then put through the hash function. 13 01:06.690 --> 01:13.560 So the resulting hash is created from both the password as well as that random unique salt. 14 01:13.680 --> 01:20.400 So that means no matter how simple the password of the user is adding that salt increases its complexity 15 01:20.490 --> 01:26.360 increases the number of characters and we make our user database a lot more secure. 16 01:26.400 --> 01:32.370 So consider the previous problem that we saw in the last lesson where we covered hacking 101. 17 01:32.370 --> 01:37.860 Now we know that three of our users have the same password and we figured that out because they all 18 01:37.860 --> 01:39.180 had the same hash. 19 01:39.180 --> 01:47.730 Now on the other hand, if we had generated a random set of characters which is the salt and combined 20 01:47.760 --> 01:54.150 the password with the salt in order generate the hash then they won't have the same hash in our user 21 01:54.150 --> 01:55.060 database. 22 01:55.080 --> 01:59.160 So let's try and generate Emily's hash from her password. 23 01:59.160 --> 02:03.110 So we know that her password is qwerty and we generate a random salt. 24 02:03.120 --> 02:10.980 So then let's go ahead and put in her password, qwerty, and then we append at the end that random salt 25 02:11.010 --> 02:15.420 that we generated and we end up with a hash. 26 02:15.600 --> 02:24.960 Now this hash however is not the same as Tony's hash or Angela's hash because the salt is different 27 02:25.050 --> 02:26.040 each time. 28 02:26.070 --> 02:29.460 Now the salt is something that the user doesn't have to remember. 29 02:29.640 --> 02:34.510 And instead it's stored in the database along with the hash. 30 02:34.830 --> 02:40.680 So that means when the user types in their password when they try to login, you combine their password 31 02:40.800 --> 02:46.470 with the salt and if you generate the same hash then they must have had the same password. 32 02:46.470 --> 02:47.580 It's kind of clever isn't it? 33 02:48.150 --> 02:54.180 And on our database of course we wouldn't be storing their passwords but only the salt and the hash. 34 02:54.270 --> 03:02.100 Now consider our previous statistics. You can generate about 20 billion MD5 hashes per second. 35 03:02.100 --> 03:09.570 So even if we added a salt and we made it harder to generate a hash table, with some of the latest 36 03:09.600 --> 03:16.830 GPUs, you can still probably generate a hash table with all salt combinations relatively quickly. 37 03:16.830 --> 03:20.090 So what else can we do to increase the security? 38 03:20.520 --> 03:23.990 Well, we can use something other than MD5 39 03:23.990 --> 03:24.530 right? 40 03:24.600 --> 03:32.580 Another hashing algorithm that's valued because it's incredibly slow. And this is where bcrypt comes 41 03:32.580 --> 03:33.150 in. 42 03:33.210 --> 03:40.770 This is one of the industry standard hashing algorithms that developers use to keep their users passwords 43 03:40.770 --> 03:46.560 safe. Because while you can calculate 20 billion MD5 hashes per second, 44 03:47.040 --> 03:55.890 even the latest and the greatest GPUs in 2019 can still calculate only about 17,000 bcrypt hashes 45 03:55.890 --> 04:03.270 per second which makes it dramatically harder for a hacker to generate those pre compiled hash tables. 46 04:03.690 --> 04:10.200 An a salted hash table instead of taking something like three seconds if it was hashed with MD5, 47 04:10.500 --> 04:12.220 if it was hashed using bcrypt 48 04:12.240 --> 04:16.710 it would take you something like 8 months, which is not really worth a hacker's while. 49 04:16.770 --> 04:22.800 They'll probably go and search out a company that has less security enabled. And to make our passwords 50 04:22.980 --> 04:25.950 even more secure when we're using bcrypt 51 04:25.950 --> 04:32.970 it has a concept of what's called Salt rounds. How many rounds you're going to salt your password with? 52 04:33.330 --> 04:39.680 And obviously the more rounds you do the saltier your password and also the more secure it is from hackers. 53 04:39.690 --> 04:42.100 So what exactly are salt rounds? 54 04:42.450 --> 04:50.460 Well let's say that our original user password was qwerty and we generate a random set of characters 55 04:50.610 --> 04:52.530 as the salt. 56 04:52.530 --> 04:55.660 So now we have qwerty and a random set of salt. 57 04:55.860 --> 05:01.140 We pass it through our hash function, bcrypt, and we end up with a hash. 58 05:01.170 --> 05:03.810 Now that's one round of salting. 59 05:03.810 --> 05:10.650 If we wanted to have two rounds of salting, then we take the hash that was generated in round 1 and we 60 05:10.650 --> 05:17.970 add the same salt from before. And now we run it through bcrypt the hash function again and we end up 61 05:18.030 --> 05:25.190 with a different hash. And the number of times you do this is the number of salt rounds. 62 05:25.200 --> 05:32.760 Now the reason why this is genius is because as computers get faster, remember that Moore's Law says 63 05:32.760 --> 05:40.410 that every year the number transistors in a computer chip almost doubles and the cost of that faster computer 64 05:40.500 --> 05:41.310 halves. 65 05:41.340 --> 05:45.320 So every year you get more computing power for less money. 66 05:45.390 --> 05:50.990 And this is where salt rounds comes in. When you're hashing your passwords using bcrypt 67 05:51.150 --> 05:55.350 you can set the number of rounds you want to salt your password. 68 05:55.350 --> 06:02.970 So that means maybe this year in 2019 you salted 10 rounds but maybe next year you can increase that 69 06:02.970 --> 06:07.840 number to 12. And for every increase in that number 70 06:08.010 --> 06:12.280 the amount of time that it takes to hash your password doubles. 71 06:12.450 --> 06:19.620 And so that means you don't have to change your hashing algorithm or update your code other than simply 72 06:19.620 --> 06:22.710 changing one number to keep up with the times. 73 06:22.740 --> 06:30.390 So just to review, coming back to that user database we'll have each user's username stored, we'll have 74 06:30.390 --> 06:38.670 their randomly generated salt stored and then we'll store their hash after a set number of salting rounds. 75 06:40.240 --> 06:45.740 And when it comes to checking their password when they login, we'll take the password that they put in 76 06:45.760 --> 06:51.700 combine it with the salt that's stored in the database and run it through the same number of salting 77 06:51.700 --> 06:57.970 rounds until we end up with the final hash and we compare the hash against the one that's stored in 78 06:57.970 --> 07:02.570 the database to see if they've entered the correct password. 79 07:02.620 --> 07:04.210 So let's give that a go 80 07:04.210 --> 07:11.340 in real life and implement bscript and salting rounds into our website's authentication. 81 07:11.620 --> 07:18.340 Now the package that we're going to be using to hash our passwords using bcrypt is also called bcrypt 82 07:18.730 --> 07:22.900 and you can find the documentation for it as always on NPM. 83 07:22.900 --> 07:28.000 Now bcrypt is a little bit peculiar about the version compatibility with Node. 84 07:28.210 --> 07:35.530 So if you're at all in doubt, be sure to first check your Node version by typing "node --version" 85 07:35.830 --> 07:37.150 or "node -v". 86 07:37.360 --> 07:42.640 And you can see that currently I'm running the latest stable release of Node which is 10.15 87 07:42.640 --> 07:46.430 .0 at this current point in time. 88 07:46.450 --> 07:53.170 Now if you ever want to know what the current stable version is for when you are looking at this video 89 07:53.200 --> 07:59.530 so this will update weekly or monthly, so by the time you're watching this video this number might already 90 07:59.530 --> 08:00.890 be higher. 91 08:00.940 --> 08:06.210 So when you check out the Node version, you can see that depending on your Node version 92 08:06.370 --> 08:13.240 they also have a bcrypt version that is compatible with that version of Node and they're very specific 93 08:13.330 --> 08:17.680 about not supporting the unstable versions of Node. 94 08:17.710 --> 08:24.220 So anything that is a odd number bcrypt is not keen to support because it's less stable, it has more 95 08:24.220 --> 08:28.740 chances of bugs and they always recommend you to use the latest stable version. 96 08:31.010 --> 08:38.390 So if you have a older version of Node or if you have even a too new version of Node, how can you go 97 08:38.390 --> 08:43.350 back to this version that's on the left hand side here on the NOde.js website? 98 08:43.970 --> 08:51.050 Well you could use something called nvm. And you can install nvm by going to its GitHub repository 99 08:51.380 --> 08:56.870 and simply copying this line of code and pasting it into your terminal. 100 08:56.870 --> 09:03.170 And once you've got it installed, restart your terminal, so close it down and open it again, and you should 101 09:03.170 --> 09:09.800 be able to check your version by writing "nvm --version" and if you get a version back then 102 09:09.800 --> 09:15.830 that means it's definitely installed and you can use it to update or downgrade your Node version. 103 09:15.830 --> 09:21.620 So we're going to aim for 10.15.0 or whatever it is that you see when you go on 104 09:21.620 --> 09:23.190 to nodejs.org, 105 09:23.210 --> 09:30.260 the long term support version. And we're going to use nvm to install Node on that version by simply 106 09:30.260 --> 09:32.380 writing "nvm install 107 09:32.410 --> 09:41.480 10.15.0" and hit enter and it will download and install that latest stable version 108 09:41.570 --> 09:44.530 of Node for you. Now 109 09:44.660 --> 09:51.680 once you've got the latest stable version downloaded and installed, you can go ahead and look for the 110 09:51.680 --> 09:54.560 compatible version of bcrypt. 111 09:54.560 --> 09:59.570 So at the moment we're on version 10 and bcrypt should be three or above. 112 09:59.570 --> 10:10.430 Now at this current point in time if I simply try and cd over to my secrets project and run "npm i 113 10:10.850 --> 10:17.810 bcrypt" then you can see I get some warnings and I suspect this is probably only going to happen for 114 10:17.810 --> 10:24.170 these few days while the bcrypt team scrambles to try and update their code. 115 10:24.170 --> 10:27.000 But if you get something similar like I do, 116 10:27.110 --> 10:34.910 how would you investigate to see how to fix this or whether if you even need to fix it? With every NPM 117 10:34.910 --> 10:42.530 package there's always a link to the repository where the code is hosted on GitHub. And on GitHub you 118 10:42.530 --> 10:49.100 can always explore the issues that people are having while they're trying to use this repository. And 119 10:49.100 --> 10:52.920 you can see that recently 3 days ago, five days ago, 120 10:53.060 --> 11:00.260 everybody seems to be having issues with installing bcrypt. And if you click on it you'll see a discourse 121 11:00.320 --> 11:08.000 or a chat or messages between the creator of the repository and people who are experiencing problems. And you 122 11:08.000 --> 11:12.670 can see whether if you are getting similar problems. Now we don't have as bad as an issue 123 11:12.680 --> 11:18.620 as this guy because they're actually getting errors and they're not actually getting it installed. And 124 11:18.650 --> 11:25.580 if you read through this you can see what the solutions are that people are recommending. And at the 125 11:25.580 --> 11:32.330 point in time where I'm running it the easiest way is to simply install a slightly older version of 126 11:32.330 --> 11:40.300 bcrypt, 3.0.2 whereas the most current version is 3.0.3. 127 11:40.400 --> 11:47.990 So in order to install a slightly older version using NPM you still write npm i for install and then 128 11:47.990 --> 11:53.570 you add in the name of the package and then you have an @ sign and after the @ sign comes the version 129 11:53.570 --> 11:54.110 that you want. 130 11:54.110 --> 11:57.950 So I want 3.0.2. 131 11:57.950 --> 12:05.360 So that is the version that NPM is going to install for me. And you can see that when I change my installation 132 12:05.690 --> 12:14.270 command I no longer get all of these problems and I have my package successfully installed. 133 12:14.270 --> 12:16.280 So you might not experiences at all. 134 12:16.280 --> 12:21.740 You might not get any problems at all other than maybe all two NPM warnings because we don't have a 135 12:21.740 --> 12:26.820 description or a repository for our packages over here. 136 12:27.170 --> 12:30.320 But other than that you might actually have no problems. 137 12:30.440 --> 12:36.110 But if you do experience an issue with bscript or any other package in the future you'll know how to 138 12:36.110 --> 12:41.990 investigate the issue and see if there are some solutions being offered for that particular issue. 139 12:42.240 --> 12:48.680 All right, so now that we have bcrypt successfully installed in our project, the next step is to actually 140 12:48.680 --> 12:49.530 use it. 141 12:49.610 --> 12:56.750 So we're gonna go ahead and swap out MD5 and instead we're going to be using bcrypt. So bcrypt equals 142 12:56.750 --> 12:59.690 require bcrypt. 143 12:59.690 --> 13:05.250 Then we defined the number of salt rounds. So at the moment 10 should be more than sufficient. 144 13:05.360 --> 13:11.750 And if you remember that the more that you increase the number the harder your computer will also have 145 13:11.750 --> 13:13.970 to work to generate those hashes. 146 13:13.970 --> 13:21.830 And if you scroll down it actually shows you how long it will take to generate your hashes or how many 147 13:21.830 --> 13:25.100 hashes are created depending on how you change this number. 148 13:25.100 --> 13:27.630 So if you set that salt round number to 31 149 13:27.770 --> 13:34.930 then on a 2GHz core you can expect to take two days or three days to generate a hash which is which 150 13:34.930 --> 13:39.670 might look like your app is crashing but it's actually just hashing away. 151 13:39.730 --> 13:47.200 So at least for 2019 and 2020, I would recommend keeping the salt round at 10. And to actually use 152 13:47.200 --> 13:47.860 bcrypt, 153 13:47.860 --> 13:53.920 we're going to use the hash function passing in the password that the user has typed in when they registered 154 13:54.340 --> 14:00.880 and also the number of rounds of salting we want to do and bcrypt will automatically generate the random 155 14:00.880 --> 14:05.740 salt and also hash our password with the number of salt rounds that we designed. 156 14:06.130 --> 14:10.430 So let's go ahead and implement that inside our register post route. 157 14:10.480 --> 14:13.090 So inside are app.post for register 158 14:13.090 --> 14:19.300 I'm going to paste those two lines of code that I've copied over from the documentation and inside this 159 14:19.300 --> 14:26.800 callback function is when we would have generated the final hash after 10 rounds of salting and also 160 14:26.800 --> 14:28.690 passing in a password. 161 14:28.690 --> 14:34.180 Now the password that we should pass in here is of course the req.body.password which is what 162 14:34.180 --> 14:40.570 the user typed in to the password field when they tried to register. And inside this callback function 163 14:40.620 --> 14:45.490 we'll have access to this hash that we can store into our database. 164 14:45.490 --> 14:51.640 So I'm going to select the rest of this code and simply paste it in here for it to run and create our 165 14:51.640 --> 14:58.510 user only once we've generated our hash. And I'm gonna substitute the password field here for the hash 166 14:58.510 --> 15:02.220 that we generate and then we're going to do exactly the same as before. 167 15:02.230 --> 15:08.890 We're going to save our new user along with their email and the hashed password into our database. 168 15:08.890 --> 15:12.700 So let's go ahead and run this and see if it works. 169 15:12.760 --> 15:18.790 So be sure to remove all the mentions of MD5 if you're going to remove that package from your 170 15:18.790 --> 15:19.480 project. 171 15:19.480 --> 15:27.430 You can see here I'm getting a warning. I have in my app.jss on line 12 I've got a console log 172 15:27.520 --> 15:32.120 that uses my MD5 package which is now of course removed. 173 15:32.140 --> 15:33.700 So let's go ahead and fix that. 174 15:34.030 --> 15:41.050 So on line number 12 I've got my console logs so I'm simply going to remove these two lines. 175 15:41.050 --> 15:46.720 So let's go ahead and hit save and nodemon and restart and you can see now our server has started 176 15:47.050 --> 15:49.160 without any problems. 177 15:49.330 --> 15:51.260 So whenever you're removing packages 178 15:51.340 --> 15:56.720 be careful that you you're not still using it somewhere inside your code. 179 15:57.040 --> 15:59.420 And let's head over to localhost:3000 180 15:59.440 --> 16:11.080 let's register a brand new user and this user is going to be user@bcrypthash.com and I'm 181 16:11.080 --> 16:15.600 completely making up these emails but it just means that when we look at it in our database it will 182 16:15.600 --> 16:19.680 be easier to see which user was hashed with which hash function. 183 16:19.690 --> 16:26.950 So this user is a bad user because they're going to use a really simple password 123456. 184 16:27.220 --> 16:29.320 And we're going to register. 185 16:29.320 --> 16:35.980 So we've successfully gone over to discover the secret page which means that our user should have been 186 16:35.980 --> 16:38.710 successfully saved into our database. 187 16:38.770 --> 16:41.360 So let's go ahead and check it out. 188 16:41.440 --> 16:47.290 You can see that our last user, the one that we registered just now, has that email user@bcrypthash 189 16:47.290 --> 16:52.440 .com and their password is quite long 190 16:52.480 --> 16:59.710 and it is a hash generated using bcrypt as well as 10 rounds of salting. 191 16:59.740 --> 17:06.550 So if you decide to try and search for this on Google or wherever it may be or any sort of hash table, 192 17:06.550 --> 17:14.080 rainbow table, whatever it may be, you should not be able to discern the user's original password which 193 17:14.080 --> 17:15.010 is key. 194 17:15.010 --> 17:18.700 Now what about when the user tries to login? 195 17:18.730 --> 17:26.830 So in our login route instead of using MD5 to rehash the password that they've put in we're 196 17:26.820 --> 17:34.020 going to be using bcrypt. And the way that they tell us to check our password is to use bcrypt. 197 17:34.030 --> 17:38.710 compare and generate a hash using this line of code. 198 17:38.710 --> 17:44.710 So let's go ahead and delete this MD5 part because we're no longer using it and instead we're 199 17:44.710 --> 17:50.380 just pulling in the username and the password that the user typed in on the login page. And then we're 200 17:50.380 --> 17:57.070 going to look through our database of users and find one where their email matches the user name of 201 17:57.070 --> 18:03.490 the one that's currently trying to login. And once we've found that person then we have to check to 202 18:03.490 --> 18:10.120 see if the password that's stored is equal to the password that's currently being entered on the log 203 18:10.120 --> 18:16.750 in page and this is the part where we're going to substitute with the bcrypt compare method that we 204 18:16.750 --> 18:17.710 just copied over. 205 18:17.830 --> 18:25.030 So let's go ahead and paste that into here and we're running this compare method and we're comparing 206 18:25.420 --> 18:30.610 the plain text password which is the one that the users currently entered in, 207 18:30.730 --> 18:39.050 so we'll substitute that with password against the hash that we've got stored in our database which 208 18:39.050 --> 18:49.970 is stored inside the foundUser.password field. Which is basically this over here. And then we get 209 18:49.970 --> 18:53.860 to check to see if the result is actually true. 210 18:53.900 --> 18:58.180 Now at this point some of you might have realized that there's a bit of a problem here 211 18:58.240 --> 18:58.580 right? 212 18:58.640 --> 19:07.370 Because in this bcrypt compare method the callback that they've defined uses an error and a res. 213 19:07.430 --> 19:11.480 Now where else have we defined a res? Up here of course. 214 19:11.510 --> 19:19.310 So in our callback if we want to do res.render inside this bcrypt method, then we have to rename 215 19:19.310 --> 19:25.830 this something else just so that our code doesn't get confused which res we're trying to use. 216 19:25.850 --> 19:32.660 So let's go ahead and rename this to result which makes it different from this one which means that 217 19:32.780 --> 19:43.730 inside here we can check to see if the result of this comparison is equal to true which means that the 218 19:43.820 --> 19:50.070 password after hashing with the salt is equal to the hash that we've got stored in our database, 219 19:50.180 --> 19:57.170 then that means that the users got the correct login password and we should res.render our secrets 220 19:57.170 --> 19:57.890 page. 221 19:58.100 --> 20:04.220 So let's go ahead and save our code and check that our server is still running without any errors. 222 20:04.220 --> 20:08.200 And let's go back to our home page and try to log in that user. 223 20:08.300 --> 20:16.130 So we've got our user@bcrypthash.com and their password was 123456. Hit log in and we get 224 20:16.130 --> 20:20.820 taken to the secret page which means that that comparison was successful. 225 20:20.930 --> 20:21.980 So that's it. 226 20:21.980 --> 20:28.970 We've managed to implement bscript along with salting and 10 rounds of salting at that to massively 227 20:28.970 --> 20:35.570 secure our user database and make it pretty much impossible to hack using something like a hash table 228 20:35.570 --> 20:41.600 or dictionary attack. But we can still level up more and we're going to discover that in the next lesson.