CSRF Protection

The documentation is constantly evolving and updated alongside the project's progress. Since it is developed in parallel with the code, some sections may temporarily refer to earlier versions of the system-these are gradually adapted to the current state of the application. If you notice any outdated information, please report it or open an Issue / Pull Request.

Documentation

# CSRF Protection

Cross-Site Request Forgery (CSRF) protection helps prevent a third-party site from causing a user's browser to submit an unwanted request to your application.

DBM Framework provides CsrfTokenManager for validating a submitted token against the token stored in the current session. The manager validates tokens; it does not generate them. In templates, use getCsrfToken() to obtain a token for a form.

# How it works

  1. Render a form and include a CSRF token in a hidden field.
  2. The browser submits the token with the form.
  3. The controller validates the submitted token using

CsrfTokenManager.

  1. Reject the request if the token is missing, invalid, or expired.
  2. Continue with the requested operation only after validation

succeeds.

# 1. Add a token to the form

Use the template helper getCsrfToken():

<form method="POST" action="/example/submit">
    <input
        type="hidden"
        name="csrf_token"
        value="{{ $this->getCsrfToken() }}"
    >
    <button type="submit">Submit</button>
</form>

The helper reads the token from the session and creates one when it is missing or expired. In the current implementation, the token is refreshed after 15 minutes.

Session support must be enabled, and the session must be available when the template is rendered and when the request is validated. Configure the application's session handling or session middleware accordingly.

# 2. Validate the token in the controller

Inject CsrfTokenManager and validate the submitted value before processing the form:

use Dbm\Http\Controller\BaseController;
use Dbm\Security\CsrfTokenManager;
use Psr\Http\Message\ResponseInterface;

final class ExampleController extends BaseController
{
    public function __construct(
        private readonly CsrfTokenManager $csrf,
    ) {}

    public function submit(): ResponseInterface
    {
        $token = $this->request()->getPost('csrf_token');

        if (!is_string($token) || !$this->csrf->isValid($token)) {
            // Reject the request; do not perform the requested operation.
            return $this->redirect('example_form');
        }

        // Process the submitted data only after CSRF validation succeeds.
        // ...

        return $this->redirect('example_form');
    }
}

Replace example_form with a route name registered by your application. The example redirects after an invalid token; applications may instead return an HTTP 403 response using their configured response-handling approach. If you use a flash message, keep the message generic and ask the user to reload the form.

CsrfTokenManager::isValid() returns true only when the supplied token is a string and matches the token stored in the session. The comparison uses hash_equals().

# Important security notes

  • Validate the token before performing any operation that changes

application state.

  • Do not put CSRF tokens in URLs.
  • Use POST (or another appropriate non-safe HTTP method) for

state-changing form submissions; do not change application state through GET requests.

  • CSRF validation does not authenticate the user and does not

authorize an operation. Protect the route with the application's authentication and permission checks as well.

  • Keep session handling consistent between token generation and

validation.

  • A token can expire. If validation fails, ask the user to reload the

form and submit it again.

  • CSRF tokens are one part of a broader security design; they do not

replace input validation, output escaping, or route access control.

helpers, permissions, JWT, passwords, and rate limits.

including getCsrfToken().

Keep relative links aligned with the actual filenames used by your documentation site.