Symfony bundle that provides Cross Site Request Forgery (CSRF or XSRF) protection for client-side applications

Overview

CSRF Cookie Bundle

This Symfony bundle provides Cross Site Request Forgery (CSRF or XSRF) protection for client-side applications requesting endpoints provided by Symfony through XHR.

Heavily influenced and inspired by DunglasAngularCsrfBundle

Requirements

  • Symfony >= 5.x

Working method

To store the CSRF token client-side a cookie containing the token can be set by one or more predetermined routes. The bundle is pre-configured in a way that modern client-side http clients such as Axios will automatically pick up said cookie. On subsequent requests to Symfony the CSRF token can then be added to the HTTP header to be validated server-side. Again, some clients may already do so automatically e.g. Axios.

Installation

Use Composer to install this bundle:

composer require dneustadt/csrf-cookie-bundle

General Configuration

# config/packages/dneustadt_csrf_cookie.yaml
dneustadt_csrf_cookie:
    # Generally enable/disable the CSRF protection
    enable: true
    # ID used to generate token
    id: csrf
    # Name of the cookie the token is stored in
    name: XSRF-TOKEN
    # Cookie expiration
    expire: 0
    # Cookie path
    path: /
    # Cookie domain
    domain: null
    # Cookie secure
    secure: false
    # Name of the HTTP header the token is expected to be stored in
    header: X-XSRF-TOKEN
    # Cookie same site policy
    sameSite: lax

Routes Configurations

Routes can be set up to either provide (create) a token, be secured by (require) a token or both.

Since the defaults of a single route or a route collection are used to configure the behaviour it is possible to do so either by means of configuration files or annotations.

# config/routes.yaml
api_controllers:
    resource: ../src/Controller/Api
    type: annotation
    defaults:
        csrf:
            # bool or array of allowed methods
            create: true
            # bool or array of allowed methods
            require:
                - 'POST'
                - 'PUT'
                - 'PATCH'
                - 'DELETE'
            # array of route names to be excluded from create/require in this collection
            exclude:
                - 'app_api_blog_index'
            # additional condition using ExpressionLanguage syntax
            condition: 'request.isXmlHttpRequest()'

For more information on conditions see ExpressionLanguage

As annotation:

// src/Controller/Api/ExampleController.php
namespace App\Controller\Api;

// ...

class ExampleController extends AbstractController
{
    /**
     * @Route("/api/index", methods={"GET","HEAD"}, defaults={"csrf": {"create": true}})
     */
    public function index()
    {
        // ...
    }
}

Symfony Form Component

Built-in CSRF Protection of forms will be automatically disabled for routes that are configured to be secured by means of the token stored in the HTTP header, provided said token can be successfully validated.

Comments
  • Is it correct that the source says 'cookieheader' twice?

    Is it correct that the source says 'cookieheader' twice?

    https://github.com/dneustadt/DneustadtCsrfCookieBundle/blob/2640428b643c4306641e8e9e1b92e9fce2ab9ec2/Service/CsrfRequestEvaluator.php#L102-L110

    headers->cookieHeader : cookies->cookieHeader

    This doesn't seem correct.


    I have - according to the README - a default route config that says XSRF-TOKEN for cookie-name, and X-XSRF-TOKEN for header name.

    On a request, I receive the cookie XSRF-TOKEN. But if I make another request with that cookie, the CSRF is still invalid. However, if I send another request with a cookie with the name X-XSRF-TOKEN it works... !?

    Also, by copying the value from the XSRF-TOKEN cookie and specifying it in a 'X-XSRF-TOKEN' header, it works. But this means copying the cookie to a header, which means accessing it from JavaScript which means no 'cookie.httponly'.

    Also, when I reply with a cookie with X-XSRF-TOKEN I now receive three cookies. The session-cookie, a XSRF-TOKEN cookie and a X-XSRF-TOKEN cookie. Something is acting up :).

    Quick fix for me is to alter the default-route config to set both 'headername' and 'cookiename' to XSRF-TOKEN. Now, when I receive a cookie XSRF-TOKEN it works when I reply with that exact same cookie.

    Which means on JavaScript-side I don't have to code anything, cookies are handled by the browser, and now the cookie-settings can be set back to 'httponly' and 'secure' as it should be.

    opened by jorismak 1
  • Two requests are required to log in via API

    Two requests are required to log in via API

    Hello there! This is my first issue. We are developing an API for a mobile app and we are working in the json_login with symfony 5.1.5 and we have implemented this bundle to give CSRF Protection to the app. The problem is that we have to make two requests to the json_login route to get XSRF Cookie and log in. Is there anyway to solve this problem???? I enclose a screenshot of my code `/** * @Route("/json_login", name="json_login", methods={"POST"}, defaults={"csrf": {"create": true}}) * @param IriConverterInterface $iriConverter * @param TokenStorageInterface $tokenStorage * @param Request $request * @return Response */ public function jsonLoginAction(IriConverterInterface $iriConverter, TokenStorageInterface $tokenStorage, Request $request) {

        if(!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
            return $this->json([
                'error' => 'Invalid Request!!!'
            ], 400);
        }
    
    
         $response = $this->json([
            'user' => $iriConverter->getIriFromItem($this->getUser())
        ]);
    
        return new JsonResponse($response->getContent(), 201);
    }
    

    ` That's my json_login code

    dneustadt_csrf_cookie: Generally enable/disable the CSRF protection enable: true ID used to generate token id: csrf Name of the cookie the token is stored in name: XSRF-TOKEN Cookie expiration expire: 0 Cookie path path: / Cookie domain domain: ***************** Cookie secure secure: false Name of the HTTP header the token is expected to be stored in header: X-XSRF-TOKEN Cookie same site policy sameSite: lax

    And that's my configuration

    opened by nandomindway 1
  • The CSRF token is invalid empty Please try to resubmit the form even when present

    The CSRF token is invalid empty Please try to resubmit the form even when present

    I was getting empty cookie as the code was accessing request header in vendor/dneustadt/csrf-cookie-bundle/CsrfRequestEvaluator.php public function isTokenValid(Request $request, bool $throwException = true): bool { $token = $request->header->get($this->cookieHeader);

        if (empty($token)) {
            if ($throwException === false) {
                return false;
            }
    
            throw new AccessDeniedHttpException('The CSRF token is invalid empty Please try to resubmit the form.');
        }
    

    I changed $request->header to $request->cookies and the issue is fixed public function isTokenValid(Request $request, bool $throwException = true): bool { $token = $request->cookies->get($this->cookieHeader);

        if (empty($token)) {
            if ($throwException === false) {
                return false;
            }
    
            throw new AccessDeniedHttpException('The CSRF token is invalid empty Please try to resubmit the form.');
        }
    
    opened by kotrakesh 0
  • It creates new token everytime!!

    It creates new token everytime!!

    Hello Team,

    nice to see this bundle. I was trying to replace dunglas/angular-csrf-bundle with your bundle. I see the dunglas bundle refreshed csrf token only when it expired. Otherwise, it uses the same token for the next request too. Is it possible to have an option to be added to create only token, when it expired instead of creating a token every time when we hit the set token url?

    Thanks, Arun Varghese

    opened by arunvar008 0
  • support symfony 6

    support symfony 6

    Hello, first i would like to thank you so much for providing this package

    it seems like this package is only for symfony ^5.x when i tried to install via composer i got this message:

    Problem 1
        - Root composer.json requires dneustadt/csrf-cookie-bundle ^1.0 -> satisfiable by dneustadt/csrf-cookie-bundle[1.0.0, 1.0.1, 1.0.2, 1.0.3].
        - dneustadt/csrf-cookie-bundle[1.0.0, ..., 1.0.3] require symfony/config ^5.0 -> found symfony/config[v5.0.0, ..., v5.4.9] but the package is fixed to v6.1.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
    

    BR

    opened by ZFnine0010 1
  • Symfony 4.4 compatibility

    Symfony 4.4 compatibility

    This PR adds compatibility with Symfony 4.4. It also lowers the PHP requirement from 7.2.5 to 7.1.3 to match Symfony 4.4's minimum. Also added the symfony and bundle keywords in composer.json; of course, they're not necessary, it's just a bit of SEO for the bundle.

    On a side note, I think the bundle could easily also be compatible with Symfony 4.2 (that's when Symfony started handling the SameSite cookie attribute), although I don't see a point since Symfony 4.2 and 4.3 are already unmaintained. Symfony 4.4 is going to be maintained until November 2023.

    opened by grimzy 0
Releases(1.0.3)
Owner
David Neustadt
Developer Core @shopware
David Neustadt
This is a laravel 4 package for the server and client side of datatables at http://datatables.net/

Datatable Important This package will not receive any new updates! You can still use this package, but be preparared that there is no active developme

Nils Plaschke 388 Dec 30, 2022
CORS (Cross-Origin Resource Sharing) support for Laravel and Lumen

Description This package adds Cross-Origin Resource Sharing (CORS) support to your Laravel application. The package is based on Framework agnostic (PS

null 48 Feb 1, 2020
PHP components - collection of cross-project PHP classes

PHP components Collection of cross-project PHP classes. Install: $ composer require ansas/php-component Ansas\Component\Convert\ConvertPrice Convert "

null 1 Jan 5, 2022
Jetstrap is a lightweight laravel 8 package that focuses on the VIEW side of Jetstream / Breeze package installed in your Laravel application

A Laravel 8 package to easily switch TailwindCSS resources generated by Laravel Jetstream and Breeze to Bootstrap 4.

null 686 Dec 28, 2022
Server-side handler of DataTables Jquery Plugin for Laravel 4

Project is not being maintained actively. You will most likely find a better more actively maintained fork here https://github.com/yajra/laravel-datat

Bilal Gultekin 264 Jul 2, 2022
Easy Laravel Server-Side implementation of PrimeVue Datatables

Laravel + PrimeVue Datatables This is a simple, clean and fluent serve-side implementation of PrimeVue Datatables in Laravel. Features Global Search i

Savannabits 11 Dec 29, 2022
The University of Arizona Libraries will no longer provide support for Guide on the Side.

The University of Arizona Libraries will no longer provide support for Guide on the Side. The code will remain openly available; however, UAL can no longer provide code fixes or upgrades.

The University of Arizona Libraries 66 Oct 31, 2022
Textpattern-jquery-ui-theme - The jQuery UI theme used within the Textpattern CMS admin-side.

Textpattern jQuery UI theme The jQuery UI theme used within the Textpattern CMS admin-side. Supported web browsers Chrome, Edge, Firefox, Safari and O

Textpattern CMS 12 Jan 10, 2022
Data Table package with server-side processing, unlimited exporting and VueJS components

Data Table package with server-side processing, unlimited exporting and VueJS components. Quickly build any complex table based on a JSON template.

Laravel Enso 618 Dec 28, 2022
DataTables server-side for CodeIgniter, supported both for CodeIgniter 3 and CodeIgniter 4.

CodeIgniter DataTables DataTables server-side for CodeIgniter, supported both for CodeIgniter 3 and CodeIgniter 4. Note: This library only handle the

Nur Muhammad 14 Dec 15, 2022
Laravel Boilerplate provides a very flexible and extensible way of building your custom Laravel applications.

Laravel Boilerplate Project Laravel Boilerplate provides a very flexible and extensible way of building your custom Laravel applications. Table of Con

Labs64 848 Dec 28, 2022
Laravel is accessible, powerful, and provides tools required for large, robust applications.

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be trul

Web & Mobile | eCommerce | Full-Stack Developer 4 Nov 24, 2022
Easily capture every incoming request and the corresponding outgoing response in your Laravel app.

Easily capture every incoming request and the corresponding outgoing response in your Laravel app. This package is designed to work only with the Lara

Mark Townsend 22 Nov 15, 2022
laravel zibal - transaction request package for zibal

laravel zibal transaction request package for zibal Getting Started To get a local copy up and running follow these simple steps. Installation You can

Abbas mkhzomi 4 Jan 10, 2022
Easily validate data attributes through a remote request

Laravel Remote Rule Easily validate data attributes through a remote request. This package allows you to define a subset of custom rules to validate a

H-FARM Innovation 27 Nov 20, 2022
This package can use form request just as Laravel do.

Lumen Form Request This package can use form request just as Laravel do. Installation Install by composer $ composer require chhw/form-request In

null 2 Nov 17, 2021
Filter resources with request parameters

FilterWhere Filter resources with request parameters Author: Thomas Jakobi [email protected] License: GNU GPLv2 Features With this MODX Revolu

Thomas Jakobi 1 Jul 12, 2022
đź––Repository Pattern in Laravel. The package allows to filter by request out-of-the-box, as well as to integrate customized criteria and any kind of filters.

Repository Repository Pattern in Laravel. The package allows to filter by request out-of-the-box, as well as to integrate customized criteria and any

Awes.io 160 Dec 26, 2022
This is a solution implementation for the coderbyte question, CLEAN GET REQUEST RESULT.

This is a solution implementation for the coderbyte question, CLEAN GET REQUEST RESULT. Two solutions are proposed, the first is a brute force approach while the other is an improved time complexity solution.

null 3 May 23, 2022