تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Spotting a Suspicious Field0:00

So we're here on the registration form of our demo app, and it looks like a pretty standard registration form, especially for a Laravel app, and if we've done our research, we can find out this app is running in Laravel, so we would know what to expect. And you've got the name, email address, and password fields there, which are all pretty standard and you would expect to find them if the site is running Laravel Breeze or one of the other OAuth scaffolding tools. But we also have the favorite book field at the bottom, which is different, and it's potentially something that we can play with and something we can look at as a potential flaw or weakness in the site. Because it indicates this isn't just a standard registration form, and so they haven't just

Tampering With Form Input2:03

And now we have the favorite book field, so what are we going to do? Well we could try inputting injection in here, SQL injection or cross-site scripting or something, but given we're talking about validation, I want to do something different. So I'm going to right click on the field and I'm going to go inspect. Now in the inspector we have the field here, and we can see of course that it's going in as the value of fail, as favorite is the field name that it's going into, but what if we change that, what if we try something different and modify this? Now when you're hacking and breaking into a site, and you're probing to try and find what's a possibility, what you could do, you often rely on keywords. Say if you think it's a WordPress site, you're going to look for the admin tool, like wp-admin

what's a possibility, what you could do, you often rely on keywords. Say if you think it's a WordPress site, you're going to look for the admin tool, like wp-admin is generally where you'll find the admin page. If you suspect that you could modify values on a User model, on a User record, then you're going to look at the different column names that you might expect to find on the record. In this case, I'm going to change it to admin. So now the name of this field here is admin rather than favorite, and I'm going to set it to 1, because let's face it, I guarantee many of you will be working on an app that has an admin flag on the User record called admin, and when you set it to true, it gives admin powers.

has an admin flag on the User record called admin, and when you set it to true, it gives admin powers. So set 1 in there, we've set the name of the field to admin, and I'm going to click register. There we go. We are now in the admin panel. That was pretty simple, wasn't it? So how did that work? Because granted, yes, it did work. We know it worked tweaking to there, and when we registered as the other account before, we didn't see that in there, so it worked, but why did it work?

Tracing the Vulnerable Code3:38

We know it worked tweaking to there, and when we registered as the other account before, we didn't see that in there, so it worked, but why did it work? Let's look at the code and have a look. Okay, so we're looking at the store method on the RegisteredUserController, and this is where the input comes in, and then Laravel handles it and then creates the User if it passes validation. And we know there's validation because we saw the error messages. So looking at the code here, we've got the validation at the top, we're checking the email and password fields. Email has to be unique, so there can't be an existing email in the database, and the password

email and password fields. Email has to be unique, so there can't be an existing email and database, and the password has to be confirmed. There you go, good. And then down here, we grab all of the request input and we throw it into the User model. And the User has done this, sorry, the developer has done this, because they've got the extra field like their favorite book. And maybe they were thinking of other fields they might add to there, maybe there's special cases where other fields will appear. And so they've added in that in there to catch everything and pass it in.

cases where other fields will appear. And so they've added in that in there to catch everything and pass it in. And probably a lot of you are thinking now, well, this is where mass assignment comes in, so why are they blocking mass assignment? So we'll have a look at the User model, and it turns out that they are. But there is a note there on the admin entry into the fillable array, which says we need this here for admin tools. And this is the biggest problem I have with mass assignment protection and fillable values on models like this, is that it's based on the model, not the request. And so different requests that interact with the same model might have different permissions.

on models like this, is that it's based on the model, not the request. And so different requests that interact with the same model might have different permissions. For example, when you're creating your User, you don't need or access to all those other values that you might have access to in the admin tools. But because in the admin tools you want to be able to dump the input into the User model easily, then you're going to make it fillable. But when you're creating the User for the User registration, and you still want to dump all the values in there, rather than list them out individually, well, you can't do that. And so this is the big flaw I have with fillable and mass assignable, and it all comes down

Fixing With Validated Data5:24

that. And so this is the big flaw I have with fillable and massAssignable, and it all comes down to permissions. And so this is why I prefer doing it through validation. But given I also think that validation is vitally important in your application for any user input anyway, it's the perfect place to do it. So we'll jump back over to our controller, and we'll have a look at our validation rules. So we can see at the top here, we have the two validation rules at the moment, one for email and one for password. And what we can do with the validator in Laravel, is you can actually get it to give you only

email and one for password. And what we can do with the validator in Laravel, is you can actually get it to give you only the validated values. So I can do this here, oops, $data = $request->validate(). In an array of only the validated values from the $request. In this case we'll only get email and password, because they're the two values that are there in the validation rules. If we want to access the other information as well, so the name and the favoriteBook, we need to add validation rules for them. So we'll do that now.

We also are passing it into a limited size database field, so let's give it a max length so that they can't enter in a really long string and breaks the query. These two will also apply straight away to our email, because it's also a string going into a database column, and this guarantees we're getting a string value of maximum length, and we've still got the unique users. And because it's an email address, we can also add in the email validator from Laravel, which will ensure that we only get actual email addresses that match the pattern, which again keeps things nicer and safer, and so we can send out emails to it. We'll come back to passwords in a sec, and we're left instead with favorite, which we've set as nullable, but because it is a string, we're going to have our string and max:255

We'll come back to password in a sec, and we're left instead with favorite, which we've set as nullable, but because it is a string, we're going to have our string and max:255 in there as well. So now we have a much better set of validation rules on our four inputs, and as I said before, the bit from the validator that sticks out is what we can use, and it's only going to contain those four values now, because they're being validated. So I'll grab data, throw it in here, and then I'll throw it in here. And now what we have there is the User model is only going to receive those four values. We're going to update the password and hash it, but it will only receive name, email, and favorite, and if we go back to the registration form now, and modify the field to set admin

Centralizing Password Rules8:24

We're going to update the password and hash it, but it will only receive name and email and favorite, and if we go back to the registration form now, and modify the field to set admin to 1 again, it won't create a new admin user. Okay, so let's talk about the password, because like I was saying, since we want to overvalidate everything, make sure our rules are as explicit as possible, passwords are no exception to that. So we've got required and confirmed in there, but we also want to add in string. And then we want to add in some more rules to encourage the user to use a strong password. Now rather than writing the rules in here directly, and we could do that, we could use, you know, min:8 for example, and then look at other password rules that we could add.

Now rather than writing the rules in here directly, and we could do that, we could use, you know, min8 for example, and then look at other password rules that we could add through there as well, but rather than use that method, Laravel has a method that we can use to reuse our password rules across the entire site, which is great from a security point of view, because then it means that our registration form, our profile password update form, any other form where the user sets or uses their password, sorry, any other form where the user sets their password, can use the exact same rules, and if we need to change them in any way, then we can change them in a single spot. So to use that, what we do is we add in the Password rule class, which is under Illuminate\Validation\Rules\Password, and then we want default.

So to use that, what we do is we add in the Password rule class, which is under Illuminate\Validation\Rules\Password, and then we want default. So we're telling it we want to use the default password rules as the validation rule in here. And so to define these rules, we jump over to our AuthServiceProvider, and in here we want to add in our Password rule again, but we want to go for the callback under default. So function, so you know what we'll do here is that one. And then inside here, we can call the password and we can give it our rules. So what we're going to say here to start off with, we want to default to a password that is eight characters long, and now if we go back to our registration form, and then we try submitting it again, okay, so let's try something really simple, just type in pass,

Rejecting Compromised Passwords12:08

the first letter. It's a pretty common pattern. So there is an alternative that we can use here that will make our app a lot more secure. So if I get rid of that, and we keep our minimum length, because minimum length is important. Instead what we can do is call uncompromised. And what this does is it makes a call to, have I been pwned, and their pwned passwords list. And the pwned passwords list is a list of known passwords that have been in data breaches. And if we run that in there and then we go back to the registration form, and we'll try it again.

More Validation, Not LessMass Assignment ConcernsPassword Validation

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟