‫So, everything that we did in this section so far
‫was to secure all application
‫and our users' data as good as possible.
‫And I talked about a lot of things
‫we can do to achieve that.
‫But all of this information was kind of
‫spread out all over these lectures.
‫So I decided to create this quick summary
‫with many best practices that we already implemented
‫and that we're still gonna implement
‫in the rest of this section.
‫Because security is so extremely important,
‫but unfortunately, many courses don't address it enough.
‫Now, I'm also not turning this
‫Node.js course into a security course.
‫There are better courses and experts for that.
‫But I will show you a couple of things that
‫you can do to properly secure your applications and data.
‫And I'm gonna look at a couple of common attacks
‫and give some suggestions to prevent them.
‫And first up, we have the event of a compromised database,
‫meaning that an attacker gained access to our database.
‫Of course, this is an extremely severe problem,
‫but to prevent even bigger problems,
‫we must always encrypt passwords and password reset tokens
‫just like we did in the videos in this section.
‫This way, the attacker can't at least
‫steal our users' passwords and also can't reset them.
‫Now, about actually preventing attacks,
‫let's talk about the brute force attack
‫where the attacker basically tries to guess a password
‫by trying millions and millions of random passwords
‫until they find the right one.
‫And what we can do is to make the login request really slow.
‫And the bcrypt package that we're using
‫actually does just that.
‫Another strategy is to implement rate limiting,
‫which limits the number of requests
‫coming from one single IP.
‫And this one we're gonna implement
‫in one of the next videos.
‫Also, a nice strategy is to actually implement
‫a maximum number of login attempts for each user.
‫For example, we could make it so that
‫after 10 failed attempts, user would have to
‫wait one hour until he can try again.
‫Now, I'm not going to implement this functionality
‫in this section, but please feel free
‫to experiment with it on your own.
‫It's probably a really cool learning experience
‫to code this up by yourself,
‫and it's actually not that hard.
‫All right.
‫Next up, there is the cross-site scripting attack,
‫where the attacker tries to
‫inject scripts into our page to run his malicious code.
‫On the clients' side, this is especially dangerous
‫because it allows the attacker to read the local storage,
‫which is the reason why we should
‫never ever store the JSON web token in local storage.
‫Instead, it should be stored in an HTTP-only cookie
‫that makes it so that the browser can
‫only receive and send the cookie
‫but cannot access or modify it in any way.
‫And so, that then makes it impossible for any attacker
‫to steal the JSON web token that is stored in the cookie.
‫Again, we're implementing this in a second.
‫Now, on the backend side, in order to prevent XSS attacks,
‫we should sanitize user input data
‫and set some special HTTP headers
‫which make these attacks a bit more difficult to happen.
‫And Express doesn't come with these best practices
‫out of the box, so we're gonna use middleware
‫to set all of these special headers.
‫Next, we have denial-of-service attacks.
‫And maybe you have heard of these.
‫It happens when the attacker sends
‫so many requests to a server that it breaks down
‫and the application becomes unavailable.
‫Again, implementing rate limiting
‫is a good solution for this.
‫Also, we should limit the amount of data
‫that can be sent in a body in a post or a patch request.
‫And also, we should avoid using
‫so-called evil regular expressions to be in our code.
‫And these are just regular expressions that take
‫an exponential time to run for non-matching inputs and
‫they can be exploited to bring our entire application down.
‫Okay, next up, we have the NoSQL query injection attack.
‫And query injection happens when an attacker,
‫instead of inputting valid data, injects some query
‫in order to create query expressions
‫that are gonna translate to true.
‫For example, to be logged in even without
‫providing a valid username or password.
‫It's a bit complex
‫and you should definitely Google it to learn more.
‫But what you need to know is that using Mongoose
‫is actually a pretty good strategy
‫for preventing these kind of attacks
‫because a good schema forces each value
‫to have a well-defined data tab.
‫Which then effectively makes
‫this type of attack very difficult to execute.
‫However, it's always a good idea
‫to still sanitize input data, just to be sure.
‫And we will take care of that a bit later.
‫All right, and now to finish,
‫I just have a couple of best practices and suggestions
‫on how to improve the authentication
‫and authorization mechanisms that we implemented.
‫So, the first thing I need to repeat
‫over and over and over again
‫is that in a production application,
‫all communication between server and client
‫needs to happen over HTTPS.
‫Otherwise, anyone can listen into the conversation
‫and steal our JSON web token.
‫Next, always create random password tokens.
‫Not generated from dates or something like that.
‫Because they are effectively passwords
‫and so, they should be treated as such.
‫Plus, always give them expiry dates,
‫just like we implemented it.
‫All right?
‫And we also implemented that a certain JSON web token
‫is no longer valid after the user has changed his password.
‫So, we basically revoke the token
‫as soon as the user changes the password.
‫Which makes a lot of sense, but again,
‫many tutorials out there simply do not do that.
‫Another big thing is to never ever commit
‫a configuration file, like for environment variables,
‫to a version control like Git.
‫In fact, do not upload it anywhere
‫because this file contains
‫the most sensitive data of the entire application.
‫For example, if someone gets access to
‫your JSON web token secret,
‫then your entire authentication process is compromised.
‫Okay, and now just a small detail is to
‫whenever there is an error,
‫do not send the entire error to the client.
‫So, stuff like the stack trace could give the attacker
‫some valuable insights into your system,
‫and so, of course, we don't want that.
‫Next up, we can use the csurf package
‫to fight a type of attack called Cross-Site Request Forgery,
‫which is an attack that forces a user
‫to execute unwanted actions on a web application
‫in which they are currently logged in.
‫We're not gonna do that in this section, though.
‫But I still wanted to mention it here.
‫Next, we could require the user to
‫re-authenticate before performing a high-value action.
‫For example, making a payment or deleting something.
‫Again, this is just a suggestion
‫that you can try out for yourself.
‫Another cool feature that you can implement
‫is a blacklist of untrusted tokens.
‫So, we already know that there is not really
‫a way to log users out of the application
‫if they show some malicious activity.
‫But what we can do is to create a list of untrusted tokens
‫that are then validated on each request.
‫And next up, a feature that we could have implemented is to
‫confirm the email address after an account is first created.
‫So, basically by sending a link to the user's email,
‫like many real apps actually do.
‫But I wanted to just keep things simple here,
‫which is why I didn't do this here.
‫But please feel free to just implement this yourself
‫if you feel like it.
‫Now, a big feature that many apps have
‫is the concept of refresh tokens.
‫Which are basically to remember users.
‫So, to keep them logged in forever
‫or until they choose to log out.
‫Our current implementation makes it so that
‫the user has to basically log in again
‫after the JSON web token expires.
‫But, with refresh tokens, that's no longer necessary.
‫And it's a bit complex to implement and so,
‫it's a feature for another time.
‫And finally, the last one
‫that we could have implemented is two-factor authentication,
‫which I'm sure you're familiar with.
‫Basically, with two-factor authentication,
‫after logging into the application,
‫the user needs to perform
‫a second action to really get authenticated.
‫And typically, that is to insert a code
‫sent via text message to a mobile phone.
‫So, these are a lot of functionalities
‫our authentication could have.
‫And if you want me to implement any of them,
‫please let me know so in the Q&A section.
‫And, if there is a lot of demand for one of them,
‫then I will show you how it works.
‫Okay, but again, I didn't want to
‫turn this Node.js course into
‫a whole security and authentication course.
‫And just to finish, something that we will implement
‫in the rest of the section is
‫to prevent parameter pollution.
‫For example, try to just insert two field parameters
‫into the query string that searches for all tours.
‫And if you do that, you will find that
‫there will be an error because
‫our application is not prepared for that.
‫And so, attackers try to use these kinds of weaknesses
‫to crash applications, which is, of course, not good.
‫And so, we need to fix that.
‫Okay, so this turned out to be a lot longer than I expected.
‫And there are entire courses about security
‫if you're really into security.
‫All right, but I am leaving it at this,
‫and so, let's now move on right to the next one.