Welcome Guest, Not a member yet? Register   Sign In
How does $allowedFields protect against mass assignment vulnerabilities?
#4

(This post was last modified: 09-09-2024, 09:31 AM by libsys. Edit Reason: is > if )

(09-04-2024, 08:52 AM)Renta Ardhana Wrote: Why do you modify the $allowedFields after declaring it in the Model?

I was not modifying $allowedFields, I said that to exemplify the unique ways I could have stuff protected from mass assignment vulnerabilities while using $allowedFields.

(09-04-2024, 08:52 AM)Renta Ardhana Wrote: As far as I know, an entity's attributes should be immutable, or if you want to make transformations, they should be done through a setter/getter.

Even if I had immutable entities, I would need to list every field in $allowedFields. Even if I modify stuff with setters, I still need to put those fields in $allowedFields.

IMHO the current approach is problematic because there's no easy way to explicitly insert protected data in the database, ever, no matter if massively assigned or not. Other frameworks (such as Laravel) discard attributes only on mass assignment (but not on manual assignment).

When using CI4 entities, currently there's no way to know if a field has been massively assigned or individually. In order to actually have the protection I expected, now I am indeed modifying the model's $allowedFields when setting fields manually in entities. Here is what I'm doing:

BaseModel.php
PHP Code:
<?php

declare(strict_types=1);

namespace 
App\Models;

use 
App\Entities\BaseEntity;
use 
CodeIgniter\Model;

abstract class 
BaseModel extends Model
{
    public function insert($row nullbool $returnID true)
    {
        return $this->allowEntityManuallyAssigned(
            $row,
            fn () => parent::insert($row$returnID)
        );
    }

    public function update($id null$row null): bool
    
{
        return $this->allowEntityManuallyAssigned(
            $row,
            fn () => parent::update($id$row)
        );
    }

    private function allowEntityManuallyAssigned(mixed $row, callable $callback): mixed
    
{
        if ($row instanceof BaseEntity) {
            $originalAllowedFields $this->allowedFields;
            $this->allowedFields  array_unique(array_merge(
                $originalAllowedFields,
                $row->getManuallyAssigned()
            ));
        }

        $result $callback();

        if ($row instanceof BaseEntity) {
            $this->allowedFields $originalAllowedFields;
        }

        return $result;
    }


BaseEntity.php
PHP Code:
<?php

declare(strict_types=1);

namespace 
App\Entities;

use 
CodeIgniter\Entity\Entity;

abstract class 
BaseEntity extends Entity
{
    protected array $manuallyAssigned = [];

    protected bool $isMassAssignment false;

    public function __set(string $key$value null)
    {
        parent::__set($key$value);

        if (! $this->isMassAssignment && ! in_array($key$this->manuallyAssignedtrue)) {
            $this->manuallyAssigned[] = $key;
        }
    }

    public function fill(?array $data null): static
    {
        $this->isMassAssignment true;

        parent::fill($data);

        $this->isMassAssignment false;

        return $this;
    }

    public function getManuallyAssigned(): array
    {
        return $this->manuallyAssigned;
    }


Usage examples:
PHP Code:
// 1
$entity = new SomeEntity(['allowedField' => 'value''notAllowedField' => 'value']);
$entity $model->find($model->insert($obj)); // $entity->notAllowedField == null

// 2
$entity = new SomeEntity();
$entity->fill(['allowedField' => 'value''notAllowedField' => 'value']);
$entity $model->find($model->insert($obj));  // $entity->notAllowedField == null

// 3
$entity = new SomeEntity();
$entity->allowedField 'value';
$entity->notAllowedField 'value';
$entity $model->find($model->insert($obj));  // $entity->notAllowedField == 'value' 
Reply


Messages In This Thread
RE: How does $allowedFields protect against mass assignment vulnerabilities? - by libsys - 09-05-2024, 11:05 PM



Theme © iAndrew 2016 - Forum software by © MyBB