Ergebnis 1 bis 16 von 16

Thema: Csrf Token im DC_Table-Kontext

  1. #1
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Frage Csrf Token im DC_Table-Kontext

    Hallo,

    ich habe in den letzten Tagen an meiner Erweiterung für Isotope iso_productfeed weiter gearbeitet (Der main-branch ist der aktuelle Stand).

    Ich habe darin die TC_Table erweitert um ein kleines Feedback-Kontaktformular zu integrieren. Ich habe alles soweit gut hinbekommen. Die Tokens sind identisch, aber ich bekomme trotzdem die Fehlermeldung:
    Code:
    Invalid CSRF token. Please reload the page and try again.
    beim absenden.

    Hat Jemand vielleicht das gleiche schonmal programmiert und kann mir da helfen. Ich weiß echt nicht, was da falsch läuft.

    Warscheinlich muss man sich die Erweiterung installieren um den Code zu debuggn.
    Ansonsten wären hier die zwei wichtigsten Klassen:

    1.
    Code:
    <?php
    
    namespace Bits\IsoProductfeed\Contao;
    
    use Contao\DC_Table;
    use Contao\System;
    use Contao\Environment as ContaoEnvironment;
    use Twig\Environment;
    use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    use Symfony\Component\Form\Extension\Core\Type\HiddenType;
    use Symfony\Component\Form\Extension\Core\Type\SubmitType;
    use Bits\IsoProductfeed\Form\FeedbackType;
    
    
    class DC_IsoProductfeed extends DC_Table
    {
        protected $strTable = 'tl_iso_productfeed';
    
        public function __construct($strTable)
        {
            parent::__construct($strTable);
        }
    
        public function showAll()
        {
            
            // Hole die aktuelle Request aus dem Symfony-Container
            $request = System::getContainer()->get('request_stack')->getCurrentRequest();
    
            return $this->generateForm($request) . parent::showAll();
        }
    
        private function processForm(array $data)
        {
            // Daten speichern oder verarbeiten
            return 'Formular erfolgreich verarbeitet.';
        }
    
        public function generateForm($request)
        {
            
            // Formular erstellen
            $container = System::getContainer();
            $formFactory = $container->get('form.factory');
            // Hole den CSRF-Token-Manager aus dem Container
            $csrfTokenManager = System::getContainer()->get('security.csrf.token_manager');
            $csrfToken = $csrfTokenManager->getToken('feedback_form')->getValue();
            
    
            $form = $formFactory->create(FeedbackType::class, null, [
           'action' => ContaoEnvironment::get('base').ContaoEnvironment::get('request'),
            'csrf_token' => $csrfToken, 
               
            ]);
            //var_dump('1: '. $csrfToken);
    
            $form->handleRequest($request);
    
            if ($form->isSubmitted() && $form->isValid()) {
                $data = $form->getData();
                return $this->processForm($data);
            }
    
            $twig = $container->get('twig');
    
            return $twig->render('@Contao/iso_productfeed_panel.html.twig', [
                'form' => $form->createView(),
            ]);
        }
    }
    2.
    Code:
    <?php
    
    namespace Bits\IsoProductfeed\Form;
    
    use Contao\System;
    use Bits\IsoProductfeed\Entity\Feedback;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    use Symfony\Component\Form\Extension\Core\Type\HiddenType;
    use Symfony\Component\Form\Extension\Core\Type\SubmitType;
    use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
    
    
    class FeedbackType extends AbstractType
    {
        
        
        
        public function buildForm(FormBuilderInterface $builder, array $options): void
        {
           
                $container = System::getContainer();
                $formFactory = $container->get('form.factory');
                //var_dump('2: '.$options['csrf_token']);
                $builder
                ->add('name')
                ->add('email')
                ->add('message')
                 ->add('_token', HiddenType::class, [
                    'data' => $options['csrf_token'], // Möglichkeit, CSRF-Token als Option zu übergeben
                ])
                ->add('submit', SubmitType::class, [
                    'label' => 'Senden',
                ]);
            
        }
    
        public function configureOptions(OptionsResolver $resolver): void
        {
    
            $resolver->setDefaults([
                'data_class' => Feedback::class,
                'csrf_protection' => true,
                'csrf_field_name' => '_token',
                'csrf_token_id'   => 'feedback_form',
                'csrf_token' => Null
            ]);
        }
    }
    Achso und die services.yaml:
    Code:
    # This file is the entry point to configure your own services.
    # Files in the packages/ subdirectory configure your dependencies.
    
    # Put parameters here that don't need to change on each machine where the app is deployed
    # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
    parameters: null
    
    services:
        # default configuration for services in *this* file
        _defaults:
            autowire: true      # Automatically injects dependencies in your services.
            autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
       
        Bits\IsoProductfeed\Contao\DC_IsoProductfeed:
            arguments:
                $twig: '@twig'
        Symfony\Component\Security\Csrf\CsrfTokenManagerInterface: '@security.csrf.token_manager'
        Bits\IsoProductfeed\EventListener\DataContainer\IsoProductfeedOnSaveListener:
            tags: ['contao.callback']
        Bits\IsoProductfeed\EventListener\DataContainer\IsoProductsOnSaveListener:
            tags: ['contao.callback']
        Symfony\Component\Form\FormFactoryInterface:
            alias: 'form.factory'
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        Bits\IsoProductfeed\:
            resource: ../../../src
            exclude: 
                - ../../../src/{ContaoManager,DependencyInjection,Resources}
               # - '../../../src/Backend/ConfigModule.php'
               # - '../../../src/Eventlistener/'
    Danke schonmal :-)
    Geändert von Monique Hahnefeld (31.12.2024 um 12:17 Uhr)
    Curiosity killed the cat

  2. #2
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Wenn du Symfony Forms benutzt musst du grundsätzlich folgendes beachten: https://docs.contao.org/dev/framewor...y-form-submits
    » sponsor me via GitHub or Revolut

  3. #3
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Frage

    Ich hab mich geirrt die Tokens sind nicht identisch. Ich habe die Doku gelesen. Das Problem ist das ich keine Parameter im __contruct hinzufügen kann, also hole ich den TokenManger aus den ServiceContainer.

    Ich habe jetzt überprüft das die Instanz nicht doppelt aufgerufen wird und der Token wird auch nur einmal übergeben. Es muss der Wert also irgendwie durch Symfony überschrieben werden beim generieren des Formulars im Frontend.
    Ich habe auch versucht die protection zu deaktivieren mit
    Code:
    'csrf_protection' => false,
    . Da ändert sich auch nix.

    Sollte ich das mal bei Github reporten? Vielleicht kollidiert hier Contao mit Symfony irgendwo?
    Curiosity killed the cat

  4. #4
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Zitat Zitat von Monique Hahnefeld Beitrag anzeigen
    Das Problem ist das ich keine Parameter im __contruct hinzufügen kann
    Doch, kannst du - aber welche Parameter willst du da injecten lassen?
    » sponsor me via GitHub or Revolut

  5. #5
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Standard

    Ich würde diese Parameter:
    Code:
    private readonly ContaoCsrfTokenManager $csrfTokenManager,
            #[Autowire(param: 'contao.csrf_token_name')]
            private readonly string $csrfTokenName,
    injecten wollen, um zu probieren, ob dann der Token identisch ist.
    Curiosity killed the cat

  6. #6
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Und was genau funktioniert dabei nicht?
    » sponsor me via GitHub or Revolut

  7. #7
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Standard Fehlermeldung hier

    Bits\IsoProductfeed\Contao\DC_IsoProductfeed::__co nstruct(): Argument #2 ($csrfTokenManager) must be of type Contao\ContaoCsrfTokenManager, array given, called in xxx/httpdocs/bardon.birdsinthesun.de/vendor/contao/core-bundle/src/Resources/contao/classes/Backend.php on line 416
    Geändert von Monique Hahnefeld (30.12.2024 um 14:56 Uhr)
    Curiosity killed the cat

  8. #8
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Achso, bei einem DataContainer Driver kannst du keine Dependency Injection nutzen. Vielleicht ist es besser, wenn du das Form Building und Processing in einen separaten Service auslagerst, diesen public machst und dann diesen Service vom Container in deinem DC Driver holst.
    » sponsor me via GitHub or Revolut

  9. #9
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Frage

    Ich habe jetzt mal noch was anderes Versucht. Ich habe den CsrfTokenManagerInterface gegen den ContaoCsrfTokenManager getauscht. Jetzt sind die Tokens identisch - Yeah!

    Code:
    use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
    use Contao\CoreBundle\Security\ContaoCsrfTokenManager;
    Allerdings sagt Contao immernoch:
    Invalid CSRF token. Please reload the page and try again.
    Ich weiß jetzt ehrlich gesagt nicht, was die Umstrukturierung der Klassen, bzw. die Auslagerung des FormBuildings bringen soll?
    Geändert von Monique Hahnefeld (30.12.2024 um 13:15 Uhr)
    Curiosity killed the cat

  10. #10
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Frage

    Ich habe nochmal nachgedacht und habe die Vermutung das es an der action liegen könnte und das ich nicht innerhalb eines Controllers, wessen Route registriert wäre, agiere. Kann das sein?

    Na jedenfalls lass ich das jetzt sein. Dann mach ich halt einfach n externen Link zu meinem Kontaktformular. Ich hätte es sehr schick gefunden, wenn es so gegangen wäre, aber naja
    Curiosity killed the cat

  11. #11
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Gehen wird es sicher, du musst nur dafür sorgen ein gültiges CSRF Token mit dem POST Request mitzuschicken.
    » sponsor me via GitHub or Revolut

  12. #12
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    HTML Das ist das Post Array, der Token ist mit den den ich absende identisch

    Code:
    array(6) { ["name"]=> string(17) "Monique Hahnefeld" ["email"]=> string(25) "info@monique-hahnefeld.de" ["message"]=> string(4) "Test" ["FORM_SUBMIT"]=> string(13) "feedback_form" ["REQUEST_TOKEN"]=> string(124) "7edfc66b2246cb164d257.1PghUG21C0M1W4-KnpWfuc_EEI2zRBEhukvnnr_C6M4.kMtwJD-CRAFQBL_DzvfT8oDyYdnmHWFq9Sepp_qIoJq4gWljK9Yybl0a6A" ["submit"]=> string(0) "" }
    Ich habe jetzt herausgefunden wo es als nicht Valid gilt:
    PHP-Code:
     /**
         * Skip the CSRF token validation if the request has no cookies, no
         * authenticated user and the session has not been started.
         */
        
    public function canSkipTokenValidation(Request $requeststring $tokenCookieName): bool
        
    {
            return
                !
    $request->getUserInfo()
                && (
                    
    === $request->cookies->count()
                    || [
    $tokenCookieName] === $request->cookies->keys()
                )
                && 
    $this->isSessionEmpty($request);
        } 
    Diese Funktion ist in der Contao\CoreBundle\CsrfContaoCsrfTokenManager-Klasse.

    Also hat es irgendwas mit Cookies und der Session zu tun.

    Also ich konnte jetzt noch herausfinden, dass das hier nicht hinhaut:
    PHP-Code:
    [$tokenCookieName] === $request->cookies->keys() 
    Da bin ich echt ratlos
    Geändert von Monique Hahnefeld (30.12.2024 um 21:52 Uhr)
    Curiosity killed the cat

  13. #13
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Ich verstehe es noch nicht ganz. Wo ist dein Formular nun und wohin schickt das Formular den POST Request?
    » sponsor me via GitHub or Revolut

  14. #14
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Computer

    Hi. Also ich extende den DC_Table mit dieser Klasse. Darin wird das Formular generiert. Das Formular ist so konfiguriert das es auf der selben Seite bleibt, wenn es abgesendet wird.

    PHP-Code:
    <?php

    namespace Bits\IsoProductfeed\Contao;

    use 
    Contao\DC_Table;
    use 
    Contao\System;
    use 
    Contao\Environment as ContaoEnvironment;
    use 
    Twig\Environment;
    use 
    Contao\CoreBundle\Security\ContaoCsrfTokenManager;
    use 
    Symfony\Component\Form\Extension\Core\Type\TextType;
    use 
    Symfony\Component\Form\Extension\Core\Type\HiddenType;
    use 
    Symfony\Component\Form\Extension\Core\Type\SubmitType;
    use 
    Bits\IsoProductfeed\Form\FeedbackType;


    class 
    DC_IsoProductfeed extends DC_Table
    {
        protected 
    $strTable 'tl_iso_productfeed';

        public function 
    __construct$strTable
                
    ){
                
                
    parent::__construct($strTable);
                
        }

        public function 
    showAll()
        {
            
            
    // Hole die aktuelle Request aus dem Symfony-Container
            
    $request System::getContainer()->get('request_stack')->getCurrentRequest();

            return 
    $this->generateForm($request) . parent::showAll();
        }

        private function 
    processForm(array $data)
        {
            
    // Daten speichern oder verarbeiten
            
    return 'Formular erfolgreich verarbeitet.';
        }

        public function 
    generateForm($request)
        {
            
            
    // Formular erstellen
            
    $container System::getContainer();
            
    $formFactory $container->get('form.factory');
            
    // Hole den CSRF-Token-Manager aus dem Container
            
    $csrfTokenManager System::getContainer()->get('contao.csrf.token_manager');
            
            
    $form $formFactory->create(FeedbackType::class, null, [
                
    'action' => $request->getUri(),
                
    'csrf_protection' => true,
                
    'csrf_field_name' => 'REQUEST_TOKEN',
                
    'csrf_token_id'   => 'feedback_form',
                 
    'attr' => [
                        
    'id' => 'feedback_form'// Setzt die ID des Formulars
                        
    'name' => 'feedback_form'// Setzt die ID des Formulars
                    
    ],
                
    'csrf_token_manager' => $csrfTokenManager
               
            
    ]);
            
    var_dump(session_id());
            
    var_dump($request->request->all());
            
    var_dump('1: '$csrfTokenManager->getToken('feedback_form')->getValue());
           
            
    $form->handleRequest($request);
             if (
    $form->isSubmitted() && $form->isValid()) {
                
    $data $form->getData();
                
    var_dump('Submitted Token: ' $request->request->get('REQUEST_TOKEN'));

                
    var_dump($data);exit;
                return 
    $this->processForm($data);
            }

            
    $twig $container->get('twig');

            return 
    $twig->render('@Contao/iso_productfeed_panel.html.twig', [
                
    'form' => $form->createView(),
            ]);
        }
    }
    Firefox_Screenshot_2024-12-31T09-48-15.402Z.png
    Geändert von Monique Hahnefeld (31.12.2024 um 09:49 Uhr)
    Curiosity killed the cat

  15. #15
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    37.162
    Partner-ID
    10107

    Standard

    Deine csrf_token_id ist noch falsch.
    » sponsor me via GitHub or Revolut

  16. #16
    Contao-Fan Avatar von Monique Hahnefeld
    Registriert seit
    22.11.2011.
    Ort
    Berlin
    Beiträge
    283

    Computer Danke vielmals :-)

    Ich wollt ja schon aufgeben, aber jetzt klappts

    Ich wünsche dir nen guten Rutsch und feier schön!!!
    Curiosity killed the cat

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •