All right. 1
So now that we've seen what some of the vulnerabilities might be for hashed passwords, it's time to 2
level up and learn about a way that we can prevent these types of dictionary attacks or hash table cracks. 3
And in order to do that, we have to learn about salting. 4
Now what exactly is salting? 5
Well, we already know what hashing is, 6
it's when we take a password, we run it through a hash function, and we end up with a hash that we 7
store on our database. 8
And as we saw in the last lesson, passwords that are generated by humans are extremely insecure. 9
They tend to be very short, and they tend to be dictionary words that are extremely easy to look up 10
and create a hash table for. 11
Now salting takes the hashing a little bit further. 12
In addition to the password, we also generate a random set of characters and those characters, along 13
with the user's password, gets combined and then put through the hash function, so the resulting hash 14
is created from both the password as well as that random unique salt. 15
So that means no matter how simple the password of the user is, adding that salt increases its complexity, 16
increases the number of characters, and we make our user database a lot more secure. 17
Consider the previous problem that we saw in the last lesson, where we covered Hacking 101. 18
Now we know that three of our users have the same password, and we figured that out because they all 19
had the same hash, 20
now, on the other hand, if we had generated a random set of characters, which is the salt, and combined 21
the password with the salt in order to generate the hash, then they won't have the same hash in our 22
user database. 23
So let's try and generate Emily's hash from her password so we know that her password is qwerty and 24
we generate a random salt. 25
So then let's go ahead and put in her password qwerty, 26
and then we append at the end that random salt that we generated. 27
And we end up with a hash. 28
Now this hash however, is not the same as Tony's hash or Angela's hash, because the salt is different 29
each time. 30
Now the salt is something that the user doesn't have to remember, and instead it's stored in the database 31
along with the hash. 32
So that means when the user types in their password, when they try to log in, you combine their password 33
with the salt. 34
And if you generate the same hash, then they must have had the same password. 35
It's kind of clever, isn't it? 36
And on our database, of course, we wouldn't be storing their passwords, but only the salt and the 37
hash. 38
Now consider our previous statistics. 39
You can generate about 20 billion MD5 hashes per second. 40
So even if we added a salt and we made it harder to generate a hash table with some of the latest GPUs, 41
you can still probably generate a hash table with all salt combinations relatively quickly. 42
So what else can we do to increase the security? 43
Well, we can use something other than MD5, right? 44
Another hashing algorithm that's valued because it's incredibly slow. 45
And this is where Bcrypt comes in. 46
This is one of the industry standard hashing algorithms that developers use to keep their users' passwords 47
safe. 48
Because while you can calculate 20 billion MD5 hashes per second, even the latest and the greatest 49
GPUs can still calculate only about 17,000 Bcrypt hashes per second, which makes it dramatically harder 50
for a hacker to generate those precompiled hash tables and a salted hash table instead of taking something 51
like three seconds if it was hashed with MD5, if it was hashed using Bcrypt, it would take you something 52
like eight months, which is not really worth a hacker's while. 53
They'll probably go and search out a company that has less security enabled, and to make our passwords 54
even more secure when we're using Bcrypt, it has a concept of what's called salt rounds, how many 55
rounds you're going to salt your password with. 56
And obviously, the more rounds you do, the saltier your password, and also the more secure it is 57
from hackers. 58
What exactly are salt rounds? 59
Well, let's say that our original user password was qwerty, and we generate a random set of characters 60
as the salt. 61
So now we have qwerty and a random set of salt. 62
We pass it through our hash function Bcrypt and we end up with a hash, 63
now that's 64
one round of salting, 65
if we wanted to have two rounds of salting, then we take the hash that was generated in round one and 66
we add the same salt from before, 67
and now we run it through Bcrypt the hash function again, and we end up with a different hash. 68
And the number of times you do this is the number of salt rounds. 69
Now the reason why this is genius is because as computers get faster, remember that Moore's Law says 70
that every year the number of transistors in a computer chip almost doubles, and the cost of that faster 71
computer halves. 72
So every year you can get more computing power for less money. 73
And this is where salt rounds comes in, 74
when you're hashing your passwords using Bcrypt, you can set the number of rounds you want to salt 75
your password. 76
So that means maybe this year in 2019 you salt it 10 rounds, but maybe next year you can increase 77
that number to 12. 78
And for every increase in that number, the amount of time that it takes to hash your password doubles. 79
And so that means you don't have to change your hashing algorithm or update your code, other than simply 80
changing one number to keep up with the times. 81
So just to review, coming back to that user database, we'll have each user's username stored, 82
we'll have their randomly generated salt stored, and then we'll store their hash after a set number 83
of salting rounds. 84
And when it comes to checking their password, when they log in, we'll take the password that they 85
put in, combine it with the salt that's stored in the database, and run it through the same number 86
of salting rounds until we end up with the final hash, and we compare the hash against the one that's 87
stored in the database to see if they've entered the correct password. 88
Let's give that a go in real life and implement Bcrypt and salting rounds into our website's authentication. 89
The package that we're going to be using to hash our passwords using Bcrypt is also called bcrypt, 90
and you can find the documentation for it, as always on NPM. 91
Now let's try and apply this knowledge to our project, and add hashing and salting into our password 92
storage and make it a little bit more secure. 93
Go ahead and download and extract the project file for this lesson. 94
And once you have extracted it and opened it in VS Code, it should be 9.2 Authentication Lv.2, 95
take a look inside the index.js, you'll see that we have all of the code that came from the solution 96
code at the end of the previous lesson. 97
So there's no hashing or anything happening here just yet, 98
and we're going to implement that very quickly. 99
Take a look inside the package.json, 100
you'll notice that there is a new dependency added, 101
and that's bcrypt. 102
Bcrypt is a way for us to be able to hash our passwords using the Blowfish algorithm, which is a super 103
secure, very modern way of ensuring that nobody with current computational skills should be able to 104
decode our password in a reasonable amount of time. 105
It is something that is industry standard, and we're going to use it in our project. 106
As always, first of all, cd into the correct project and then use "npm install" to add all of the node 107
modules. 108
All right. 109
So the first thing we need to do is to import that bcrypt module. 110
So, import bcrypt from "bcrypt"; 111
And one thing we should define before we start using it is the number of salting rounds. 112
So we'll call that saltRounds, 113
and I'm going to set it to 10. 114
It depends on your own individual sort of level of security you want for your app, 115
but obviously, as we explained, the more rounds of salting that happens, the more computation and more 116
time therefore is required to try and hack the original password out of the hash. 117
So if we only did two salt rounds, it would take less time to generate the hash, 118
but it would also probably allow some bad actors to be able to figure out the original password by brute 119
forcing a lot quicker. 120
So we've imported bcrypt, 121
we've added our number of salt rounds, 122
the next thing we're going to do is to actually use it. Coming into our register POST route right here, 123
we've got all of our previous code, 124
but now after we check and make sure that the user doesn't already exist and we're about to save their 125
email and password into our database, just before that happens, we're going to do our password hashing, 126
and we're going to do that by using the bcrypt module 127
and it has a method called hash(). 128
Now this method takes a number of inputs. 129
So the first one is the data that you want to hash, which is the password that the user typed into 130
the form. 131
Next is the number of salt rounds. 132
So we already have that defined as a constant up top which I said 10 in my case, 133
and it works out on a couple of computers 134
we tried to be good enough in terms of speed. 135
And then finally we have our callback which can return an error, and if there were no errors, then 136
it will return the encrypted string, which we're going to call the hash. 137
So let's create this callback. 138
And once we have that hash then the next step is to store that into our database instead of the plain 139
text password. 140
So I'm going to take all of this code up to the res.render()and put it inside this callback. 141
Now remember that because we are waiting on this query to complete without any errors, before we 142
res.render(secrets.ejs), we have to turn this callback into an asynchronous method by adding the async 143
keyword before it. 144
So now we're ready to replace this password with the hash that gets generated here. 145
And if there were any errors through the hashing process, then we need to either handle it or at the 146
very least we need to console.log() it just so that while we're testing, we know what's going on. 147
And if there were no errors, then we're going to go ahead and do the rest of the planned parts of saving 148
that user's hash and email into our database. 149
Let's go ahead and try this out. 150
Let's go ahead and start our index.js. 151
Go back to our website. 152
Go to the home page. 153
Try to register a new user. 154
So I'm just going to call it maybe test. 155
And then the password is still the same. 156
It's 123456. 157
And then I'm going to click Register. 158
So now if I go to my database and I right-click on the users to View all of them, I should now have 159
a new user, test@gmail.com, 160
and the password, 161
as you can see, even though as you saw me enter it, it was still 123456. 162
Just public announcement, 163
"Don't do that." 164
Try to have a more secure password. 165
But even though it's super insecure in terms of password, we now have a hash that's generated. 166
It's super long. 167
I definitely cannot tell that this is one, two three, four, five, six, and hopefully nobody else 168
will be able to do, if we managed to do everything correctly. 169
And that's because we did our hashing correctly. 170
So now somebody hacks into our database, they'll see this instead of this 171
and it means we've made life a little bit safer for this user. 172
I'm going to go ahead and actually delete this first entry for angela@gmail.com, because it no longer 173
actually follows our password strategy. 174
So now every new user that gets signed up on our website will have a hash for their password. 175
Now that we've done our registration and we've hashed our password for storage, the next step is to 176
figure out how to compare the password that's stored in the database against the password that the user 177
enters when they try to log in. 178
Unfortunately, with bcrypt, because we're doing many salting rounds, each time we hash the password, 179
it will not match. 180
So we can't simply just compare the stored hash against the hashed version of the login password and 181
expect them to match. 182
There's actually an extra layer of security in there with that salting, and each time the hash that's 183
generated will be different. 184
How can we then compare those two passwords? 185
Well, Bcrypt actually comes with a method called compare. 186
Right here we're going to say bcrypt. 187
and this is the method that we want to use which is compare(). 188
And this allows us to compare the data which is the data that is to be encrypted. 189
So the data that comes from the user when they try to log in and then the encrypted, which in this 190
case is of course the hash that's stored in our database, 191
and then we end up returning a callback. 192
So bcrypt.compare, 193
and the first one is the new password. 194
So I'm just going to change this to loginPassword so that we're not confused later on in our compare. 195
So we're comparing the login password, 196
and we're going to compare it against the result that comes back here which I'm going to change to the 197
"storedHashedPassword". 198
And that's the comparison that's going to be made. 199
Now the order of these two matters a great deal. 200
So don't put this one here and that one here. 201
It has to be this way 202
so that the compare() method knows which one it needs to work with and which one needs to hash. 203
And then we end up with our callback, which is going to be an error or a result, 204
and then here we can again handle any errors that occur in this process by console logging. 205
And if there were no errors, then we're simply going to check to make sure that the result is valid. 206
Then we're going to console.log(result) 207
for now. I just want to show you what it actually looks like. 208
So let's go back to our login page. 209
Use the user that has a hash password. 210
Go back to here. 211
You can see that what got console logged is the result, "true" 212
which means that all we need to do is to check if that is true, 213
then we can go ahead and res.render(), 214
but if it's false then we can again send that they got the incorrect password. 215
And we can now delete this if and else statement here. 216
Just to make sure, 217
let's try that with a wrong password. 218
I'm going to use the second worst password in the world, which is qwerty. 219
Click log in. 220
You can see we get incorrect password. 221
There you have it. 222
We've now implemented hashing and salting, and we have made our passwords much, much more secure for 223
our users. 224
And even if somebody hacks into our website, they will only be able to see this< 225
and there is no way for them to be able to get back the original password that's associated with that 226
email. 227
And if you want to allow users to log in with email and password, we're at a stage where that's already 228
pretty secure for the user. 229
In the next lesson, I'm going to talk about something slightly different. 230
We're going to talk about how to implement cookies and sessions so that when a user is logged in, they 231
can log in to access the secret page, but that login is saved as a cookie so that they don't have to 232
re-log in 233
if they came back to the website, say within a certain period of time. 234
And this is pretty common when you try to access Facebook or Gmail, you're not having to enter your 235
password again and again each time. 236
And we're going to be able to add that functionality to our website as well. 237
Keep your eyes peeled in the next lesson as we learn all about that. 238
So for all of that and more, I'll see you there.