CSRF

The Centum\Http\Csrf namespace exists to prevent cross-site request forgery attacks that could exist in HTML forms.

This component comes in three parts: Generator, Storage, and Validator.

Centum\Http\Csrf\Generator implements Centum\Interfaces\Http\Csrf\GeneratorInterface.

Centum\Http\Csrf\Storage implements Centum\Interfaces\Http\Csrf\StorageInterface.

Centum\Http\Csrf\Validator implements Centum\Interfaces\Http\Csrf\ValidatorInterface.

Centum\Http\Csrf\Generator(
);
Centum\Http\Csrf\Storage(
    Centum\Interfaces\Http\SessionInterface $session,
    Centum\Interfaces\Http\Csrf\GeneratorInterface $generator
);
Centum\Http\Csrf\Validator(
    Centum\Interfaces\Http\RequestInterface $request,
    Centum\Interfaces\Http\Csrf\StorageInterface $storage
);

The Centum\Http\Csrf namespace works by generating and storing a random string in a Centum\Interfaces\Http\SessionInterface object and making this value available for use in a <form>. By comparing the value submitted by the user and the known value from the Session, we can validate whether the POST request is genuine or not.

Wherever a POST request requires CSRF protection, the current token value can be obtained from a Storage object and injected into the view:

use Centum\Interfaces\Http\Csrf\GeneratorInterface;
use Centum\Interfaces\Http\SessionInterface;

/** @var SessionInterface $session */
/** @var GeneratorInterface $generator */

$csrfStorage = new Storage($session, $generator);

$csrfValue = $csrfStorage->get();
<form>
    <input type="hidden" name="csrf" value="<?php echo $csrfValue; ?>">

    <!-- rest of the form -->
</form>

If you’re using Twig, you can use the Centum CSRF Twig extension by simply calling the csrf() function somewhere in the form:

<form>
    {{ csrf() }}

    <!-- rest of the form -->
</form>

The CSRF Twig extension also provides the csrfValue() function that returns the raw CSRF value which is useful when dealing with AJAX form submissions:

$.post(
    {
        url: "/update-password",
        data: {
            "newPassword":        $("#newPassword").val(),
            "newPasswordConfirm": $("#newPasswordConfirm").val(),
            "csrf":               "{{ csrfValue() }}"
        }
    }
);

Regardless of how the CSRF token is placed, ValidatorInterface::validate() must be called at the top of your Form’s constructor method to validate it:

namespace App\Web\Forms;

use Centum\Interfaces\Http\Csrf\ValidatorInterface;
use Centum\Interfaces\Http\FormInterface;

class SubmissionForm implements FormInterface
{
    public function __construct(ValidatorInterface $csrfValidator)
    {
        $csrfValidator->validate();

        // ...
    }
}

Values are generated with the GeneratorInterface::generate() method:

use Centum\Interfaces\Http\Csrf\GeneratorInterface;

/** @var GeneratorInterface $csrfGenerator */

$newValue = $csrfGenerator->generate();

Values can be removed from the Session with the StorageInterface::reset() method:

use Centum\Interfaces\Http\Csrf\StorageInterface;

/** @var StorageInterface $csrfStorage */

$csrfStorage->reset();