What is the security efficacy of 'fillable'? - laravel

I'm struggling to fully understand the security efficacy of fillable and wondering what to do with columns that can't have a default value and will never be provided by the user.
A mass assignment vulnerability occurs when a user passes an unexpected HTTP request field and that field changes a column in your database that you did not expect. For example, a malicious user might send an is_admin parameter through an HTTP request, which is then passed to your model's create method, allowing the user to escalate themselves to an administrator.
https://laravel.com/docs/8.x/eloquent#mass-assignment
The above snippet from the documentation contains a good example: is_admin. That value wouldn't be directly provided by the user but it still needs to be provided during create().
Another example might be slug. This would likely come from a user-provided title value. This can't have a default value and won't be provided by the user so it needs to be fillable.
As far as efficacy goes, doesn't it make sense for there to be a class of secured input that's identified as (1) not being provided by the user and (2) is fillable? It seems like a column loses its secure-by-default status if it's listed in fillable.

The fillable prevents batch assignment. Disables the use of arrays. Thus, it is protected from external attacks.
Example:
You can protect the is_admin column:
$fillable = ['name', 'password', 'email'];
Then, to be able to update or create the value, you must explicitly set the value in the model and save it, for example:
$user->is_admin = 1;
$user->save();

Related

Cannot test laravel livewire model hidden attribute with assertSet

I have a simple LIvewire component consisting of a form to create a new User, and it work, i can tell since i've been asked to write tests after the project already reached staging.
The Livewire component use a new User instance (non presisted, i.e. user->exists is false) to store inserted data before persisting it, and the user model hides the password attribute trough the protected $hidden array.
Now, i can sucesfully create new users trough the form page in my local environment, but when it comes to testing, it gives me error.
The test
Livewire::test(
FormComponent::class,
)
->set('user.name', 'user name')
->set('user.email', 'user#email.com')
->set('user.password', 'password')
->assertSet('user.name', 'user name')
->assertSet('user.email', 'user#email.com')
->assertSet('user.password', 'password');
The error
Failed asserting that null matches expected 'password'.
What i find out
Setting my compoment user instance trough the form page goes fine because livewire recognize it as a model, so do something like user->password = 'password', while when setting it from the test with set() it access its property with the access operator as it is an array, i.e.: user['password] = 'password'.
Commenting out the password entry in the $hidden array made the test pass.
This will explain the difference in the property setting.
Conclusion
Since the $hidden array is meant to hide model properties in its array/json representation it should not interfere with automated tests, moreover when using Livewire own methods, so to me this looks like a LIvewire Bug.
Help
Does anyone have aver encountered this bug?
Update#1
I've opened an issue on Livewire github page for this.
You have diagnosed this pretty well. When Livewire serializes the User model, password is not included because it is in the $hidden array. Even though the User model has not been persisted yet, serialization is the same.
I would guess that your input fields all use the defer modifier, which is why your fields are working in the browser; however, when you call set() in the test, it simulates a Livewire request, so the $hidden attributes are being wiped.
An alternate assertion for testing the password is my recommendation here. Try asserting that the created user can login with the selected password.
$this->assertTrue(
auth()->attempt(['email' => 'user#email.com', 'password' => 'password'])
);

What to check when validator is not called in symfony 3?

I cannot find general checklist - what to check when it is not called. Can you write it?
For example code snippets where validator is not being called:
$fieldOptions['constraints'] = [
new NotBlank($constraintOptions)
];
$builder->add(
$builder
->create($formField->getId(), EntityType::class, $fieldOptions)
->addModelTransformer(
new EntityCollectionToArrayTransformer($this->registry, $fieldOptions['class'])
)
);
One of things to check - validation groups. Try commenting out any validation groups, so it would work as default. When form adds a collection of forms, those subforms validator constrains also have to have same group. https://symfony.com/doc/3.4/validation/groups.html
When validating just the User object, there is no difference between the Default group and the User group. But, there is a difference if User has embedded objects. For example, imagine User has an address property that contains some Address object and that you've added the Valid constraint to this property so that it's validated when you validate the User object.
If you validate User using the Default group, then any constraints on
the Address class that are in the Default group will be used. But, if
you validate User using the User validation group, then only
constraints on the Address class with the User group will be
validated.
In other words, the Default group and the class name group (e.g. User)
are identical, except when the class is embedded in another object
that's actually the one being validated.

Adding attribute to a user when register in Laravel 5.1

When a user Register, I want to add location data for the user.
I get those with GeoIP.
So, each time a user is created, I would like somewhere to add Country, City, etc.
I was thinking about setting Hidden fields in view, but I think it a hugly way to do it, and I'm sure there is a better way to do...
Any Idea???
Any time I create a record that needs extra data, involves inserting additional records into additional tables, etc, I create a service class. Something like "UserCreator" then I pass it the input, do any additional operations, wrap multiple database calls in a transaction and so on.
That said there are so many ways to do what you want. You could Input::merge(...) then save, you could separate the process of creating a user from your controller / route function, etc.
If you are just getting started with Laravel and/or your project is rather simple, then you probably want to look at Input::merge
I solved it using Request Contructor as said here in laracast
In the Form Request's constructor I inject \Illuminate\Http\Request. I can then add my value to the request instance as such:
public function __construct(\Illuminate\Http\Request $request)
{
$request->request->add(['date_of_birth' => implode('-', $request->only('year', 'month', 'day'))]);
}

cakePHP - creating new user account, several problems

I have two tables, users and tokens.
Each user have a activated field and each token have the {id, token, user_id, created} fields.
The way the app should work is:
On the creation, the app will -
make sure that the activated field is empty (to avoid manipulations to the submitted data).
a token will be created in the tokens table.
On update, the app will -
NOT create a new token.
NOT allow an update of any kind to the activated field.
check if a new email has been submitted, and if so: will create a new token and set the activated field to false.
I know how to activate the account through the controller and how to setup the router for that.
What I need is mainly the model configuration.
For example:
I think that the token creation should be done in the afterSave method, so - how do I determine if the method is called by an update or by a create operation?
Thanks for any help
yossi you can also specify the fields that should be saved from the form though - a whitelist of fields it is ok to save in you $this->save() call. That way you can stop a hacker passing an ID in the request, and you should just set it in the controller yourself then with $this->Token->id = whatever you have, I would personally use saveField ('activated) in conjunction with this (just saves a single field!). Fat models is best if you can but get it working first then refactor it if you have got stuck. Better than wasting lots of time writing perfect first time.
You question is unclear. If you have a default value for a field, then why not set it in the database rather than doing something in aftersave? If you need to do something that should be done only in certain circumstances, then write a custom method in your model to perform the tasks you want either on creation or update.
Edit
So, if your record has an id, then you know it exists in the database. So, the simple thing to do is (in any method) check to see if the model has an id field and that it is not empty. If it's empty, then you know that you are creating a record and you can do x task. If it isn't, then do y task.
if(isset($modelData['ModelName']['id']) && !empty($modelData['ModelName']['id'])){
//This is an update
} else {
//This is a new record
}

CakePHP Auth Loads Too Many Session Variables

Using CakePHP2.0 Beta I managed to write a custom login handler for my existing database schema. All's well, except that upon logging in I printed out the session variables stored and what Cake's Auth component did is store the entire record from the "Member" table (where my usernames+hashes come from) in session. It is storing an array with data fields that are totally irrelevant to the session. For instance it stores the date the member was created, their address, etc. All pretty useless information for me as I basically only need their ID and maybe username, name, email address.
The offending lines for me are found in: /lib/Cake/Controller/Component/AuthComponent.php line 512. It states,
$this->Session->write(self::$sessionKey, $user);
So my custom authenticate component returns $user and it throws this whole thing into the session. Now, I don't want to go about editing in the core libraries because this project is definitely going to be upgraded when 2.0 comes out. Is there any way to store less information in sessions? I want to keep this whole thing more lightweight.
Possible solution: Change my custom authentication component to only return the fields I need into the $user variable. Are there any concerns about what data I should/shouldn't be returning?
I've solved the problem using my "possible solution". In /app/Controller/Component/auth/MyController.php, I changed the "ClassRegistry::init($userModel)->find" method to have a parameter for 'fields' where I specify only the fields I need. Works like a charm.

Resources