Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Mongo CSRF Form Validation

Hi,

i have some troubles with form validation using ODM.

I have a basic form class

class Update extends Form
{
    public function getCsrf()
    {
        return $this->security->getToken();
    }

    public function initialize($entity = null, $options = [])
    {
        $id = new Hidden('id');
        $id->addValidator( new PresenceOf(['message' => '<b>ID<b> is required.']) );
        $id->setFilters(['trim', 'string']);  // ObjectID
        $id->setAttributes(['id' => null]);
        $this->add($id);

        $type = new Hidden('type');
        $type->addValidator(new PresenceOf(['message' => '<b>Type<b> is required.']) );
        $type->setDefault($options['type']);
        $type->setFilters(['trim', 'string']);
        $type->setAttributes(['id' => null]);
        $this->add($type);

        $csrf = new Hidden('csrf');
        $csrf->addValidator( new PresenceOf(['message' => 'CSRF is required.']) );
        $csrf->addValidator( new Identical( ['value' => $this->security->getSessionToken(), 'message' => 'CSRF validation failed.' ]) );
        $csrf->setAttributes(['id' => null]);
        $csrf->clear();
        $this->add($csrf);

        $name = new Text('name');
        $name->setLabel('Nom');
        $name->addValidator( new PresenceOf(['message' => 'The name is required.']) );
        $name->setAttributes( ['class' => 'form-control', 'id' => null]);
        $name->setFilters(['trim', 'string']);
        $this->add($name);
    }
}

Then when I submit form : ( sample)

public function updateAction()
    {
        $this->view->disable();

        if ($this->request->isPut() == true && $this->request->isAjax() == true) {

            $id = $this->request->getPut('id', ['trim', 'string']);
            $type =  $this->request->getPut('type', ['trim', 'string']);
            $name = $this->request->getPut('name', ['trim', 'string']);

           $entity = Model::findFirst([['_id' => new ObjectID($id)]]);

            $form = new updateForm($entity, ['type' => $type]);

            if ($form->isValid($this->request->getPut()) != false)
            {

            if ($entity->save() === true) {
                $msg['success'][] =  ['message' => 'Updated Successfully'];
            } else {
                foreach ($entity->getMessages() as $message) {
                    $msg['error'][] = ['message' => $message->getMessage()];
                }
            }

        } else {
            foreach ($form->getMessages() as $message) {
                $msg['error'][] = ['message' => $message->getMessage()];
            }
        }

            $this->response->setStatusCode(200, 'OK');
            $this->response->setJsonContent(msg);
            $this->response->send();
        }
    }

The problem is when i set entity to form CSRF token failed at validation.

I try many solution but not result.

  1. Model::findById($id) => Validation FAILED

  2. Model::findFirst([['_id' => new ObjectID($id)]]); => Validation FAILED

  3. Model::findFirst(['_id' => $id]); => return Bad Document

Any solution ?

Thx,



3.4k
Accepted
answer

I think I found the problem.

I'm using PUT method to Update and DELETE method to Delete. Then i'm using ajax to delete or update entity. exemple : $router->addDelete('/some/route/{type:[a-z]+}/delete', array( 'action' => 'delete' ))->setName('SomeRouteDelete');

And when we look at => https://github.com/phalcon/cphalcon/blob/master/phalcon/security.zep#L393 Phalcon only check on POST.

In that case I have to change all routes (addDelete and addPut) in POST, all ajax method to POST and CSRF validation in form.

now I have to use CSRF in template file

{{ hidden_field(security.getTokenKey(), "value": security.getToken()) }}

instead CSRF in form class

class DeleteForm extends Form
{
    public function getCsrf()
    {
        return $this->security->getToken();
    }

    public function initialize($entity = null, $options = [])
    {
        // Other Inputs

        $csrf = new Hidden('csrf');
        $csrf->addValidator( new Identical( ['value' => $this->security->getSessionToken(), 'message' => 'CSRF validation failed' ]));
        $csrf->setAttributes(['id' => null]);
        $csrf->clear();
        $this->add($csrf);
    }

}

and

if ($this->security->checkToken()) {
           // 
}