diff --git a/_build/redirection_map b/_build/redirection_map index daf23e274b0..c0b1b96c23d 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -124,7 +124,7 @@ /cookbook/console/style /console/style /cookbook/console/usage /console /console/usage /console -/cookbook/controller/csrf_token_validation /controller/csrf_token_validation +/cookbook/controller/csrf_token_validation /security/csrf /cookbook/controller/error_pages /controller/error_pages /cookbook/controller/forwarding /controller/forwarding /cookbook/controller/index /controller @@ -221,7 +221,7 @@ /cookbook/security/acl /security/acl /cookbook/security/acl_advanced /security/acl_advanced /cookbook/security/api_key_authentication /security/api_key_authentication -/cookbook/security/csrf_in_login_form /security/csrf_in_login_form +/cookbook/security/csrf_in_login_form /security/csrf /cookbook/security/custom_authentication_provider /security/custom_authentication_provider /cookbook/security/custom_password_authenticator /security/custom_password_authenticator /cookbook/security/custom_provider /security/custom_provider @@ -361,7 +361,9 @@ /components/yaml/introduction /components/yaml /components/yaml/index /components/yaml /console/logging /console +/controller/csrf_token_validation /security/csrf /deployment/tools /deployment +/form/csrf_protection /security/csrf /install/bundles /setup/bundles /email/gmail /email /email/cloud /email @@ -376,6 +378,7 @@ /frontend/assetic/yuicompressor /frontend/assetic /reference/configuration/assetic /frontend/assetic /security/target_path /security +/security/csrf_in_login_form /security/csrf /service_container/third_party /service_container /templating/templating_service /templates /testing/simulating_authentication /testing/http_authentication diff --git a/controller/csrf_token_validation.rst b/controller/csrf_token_validation.rst deleted file mode 100644 index e9db3189a56..00000000000 --- a/controller/csrf_token_validation.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. index:: - single: Controller; Validating CSRF Tokens - -How to Manually Validate a CSRF Token in a Controller -===================================================== - -Sometimes, you want to use CSRF protection in an action where you do not -want to use the Symfony Form component. If, for example, you are implementing -a DELETE action, you can use the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::isCsrfTokenValid` -method to check the validity of a CSRF token:: - - public function delete() - { - if ($this->isCsrfTokenValid('token_id', $submittedToken)) { - // ... do something, like deleting an object - } - } diff --git a/form/csrf_protection.rst b/form/csrf_protection.rst deleted file mode 100644 index f06b7cf3947..00000000000 --- a/form/csrf_protection.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. index:: - single: Forms; CSRF protection - -How to Implement CSRF Protection -================================ - -CSRF - or `Cross-site request forgery`_ - is a method by which a malicious -user attempts to make your legitimate users unknowingly submit data that -they don't intend to submit. Fortunately, CSRF attacks can be prevented by -using a CSRF token inside your forms. - -The good news is that, by default, Symfony embeds and validates CSRF tokens -automatically for you. This means that you can take advantage of the CSRF -protection without doing anything. In fact, every form in this article has -taken advantage of the CSRF protection! - -CSRF protection works by adding a hidden field to your form - called ``_token`` -by default - that contains a value that only you and your user knows. This -ensures that the user - not some other entity - is submitting the given data. -Symfony automatically validates the presence and accuracy of this token. - -The ``_token`` field is a hidden field and will be automatically rendered -if you include the ``form_end()`` function in your template, which ensures -that all un-rendered fields are output. - -.. caution:: - - Since the token is stored in the session, a session is started automatically - as soon as you render a form with CSRF protection. - -The CSRF token can be customized on a form-by-form basis. For example:: - - // ... - use App\Entity\Task; - use Symfony\Component\OptionsResolver\OptionsResolver; - - class TaskType extends AbstractType - { - // ... - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults(array( - 'data_class' => Task::class, - 'csrf_protection' => true, - 'csrf_field_name' => '_token', - // a unique key to help generate the secret token - 'csrf_token_id' => 'task_item', - )); - } - - // ... - } - -.. _form-disable-csrf: - -To disable CSRF protection, set the ``csrf_protection`` option to false. -Customizations can also be made globally in your project. For more information, -see the :ref:`form configuration reference ` -section. - -.. note:: - - The ``csrf_token_id`` option is optional but greatly enhances the security - of the generated token by making it different for each form. - -.. caution:: - - CSRF tokens are meant to be different for every user. This is why you - need to be cautious if you try to cache pages with forms including this - kind of protection. For more information, see - :doc:`/http_cache/form_csrf_caching`. - -.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery diff --git a/forms.rst b/forms.rst index 308d6d47d4c..4e89bfbfc8c 100644 --- a/forms.rst +++ b/forms.rst @@ -189,7 +189,7 @@ That's it! Just three lines are needed to render the complete form: Renders the end tag of the form and any fields that have not yet been rendered, in case you rendered each field yourself. This is useful for rendering hidden fields and taking advantage of the automatic - :doc:`CSRF Protection `. + :doc:`CSRF Protection `. .. seealso:: diff --git a/http_cache/form_csrf_caching.rst b/http_cache/form_csrf_caching.rst index fb8d4b9368c..1acfe38ccc3 100644 --- a/http_cache/form_csrf_caching.rst +++ b/http_cache/form_csrf_caching.rst @@ -8,7 +8,7 @@ CSRF tokens are meant to be different for every user. This is why you need to be cautious if you try to cache pages with forms including them. For more information about how CSRF protection works in Symfony, please -check :doc:`CSRF Protection `. +check :doc:`CSRF Protection `. Why Caching Pages with a CSRF token is Problematic -------------------------------------------------- diff --git a/http_cache/varnish.rst b/http_cache/varnish.rst index 43d4473b9f2..4ebd2c51c00 100644 --- a/http_cache/varnish.rst +++ b/http_cache/varnish.rst @@ -62,7 +62,7 @@ If you know for sure that the backend never uses sessions or basic authentication, have Varnish remove the corresponding header from requests to prevent clients from bypassing the cache. In practice, you will need sessions at least for some parts of the site, e.g. when using forms with -:doc:`CSRF Protection `. In this situation, make sure to +:doc:`CSRF Protection `. In this situation, make sure to :doc:`only start a session when actually needed ` and clear the session when it is no longer needed. Alternatively, you can look into :doc:`/http_cache/form_csrf_caching`. diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index df49de99512..2d36effc6c2 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -411,7 +411,7 @@ csrf_protection .. seealso:: - For more information about CSRF protection in forms, see :doc:`/form/csrf_protection`. + For more information about CSRF protection, see :doc:`/security/csrf`. .. _reference-csrf_protection-enabled: @@ -422,7 +422,7 @@ enabled otherwise This option can be used to disable CSRF protection on *all* forms. But you -can also :ref:`disable CSRF protection on individual forms `. +can also :ref:`disable CSRF protection on individual forms `. If you're using forms, but want to avoid starting your session (e.g. using forms in an API-only website), ``csrf_protection`` will need to be set to diff --git a/security.rst b/security.rst index b32a64a865d..56d87a77e6f 100644 --- a/security.rst +++ b/security.rst @@ -1291,7 +1291,7 @@ Authentication (Identifying/Logging in the User) security/api_key_authentication security/custom_authentication_provider security/pre_authenticated - security/csrf_in_login_form + security/csrf security/named_encoders security/multiple_user_providers security/multiple_guard_authenticators diff --git a/security/csrf_in_login_form.rst b/security/csrf.rst similarity index 50% rename from security/csrf_in_login_form.rst rename to security/csrf.rst index 3551c82764c..18d6747a45a 100644 --- a/security/csrf_in_login_form.rst +++ b/security/csrf.rst @@ -1,59 +1,92 @@ .. index:: - single: Security; CSRF Protection in the Login Form + single: CSRF; CSRF protection -Using CSRF Protection in the Login Form -======================================= +How to Implement CSRF Protection +================================ -When using a login form, you should make sure that you are protected against CSRF -(`Cross-site request forgery`_). The Security component already has built-in support -for CSRF. In this article you'll learn how you can use it in your login form. +CSRF - or `Cross-site request forgery`_ - is a method by which a malicious +user attempts to make your legitimate users unknowingly submit data that +they don't intend to submit. -.. note:: +CSRF protection works by adding a hidden field to your form that contains a +value that only you and your user know. This ensures that the user - not some +other entity - is submitting the given data. - Login CSRF attacks are a bit less well-known. See `Forging Login Requests`_ - if you're curious about more details. +Before enabling the CSRF protection, install the CSRF support in your project +(which in turn requires installing the Symfony Form component): -Configuring CSRF Protection ---------------------------- +.. code-block:: terminal -First, make sure that the CSRF protection is enabled in the main configuration -file: + $ composer require security-csrf form -.. configuration-block:: +CSRF Protection in Symfony Forms +-------------------------------- - .. code-block:: yaml +Forms created with the Symfony Form component include CSRF tokens by default +and Symfony checks them automatically, so you don't have to anything to be +protected against CSRF attacks. - # config/packages/framework.yaml - framework: - # ... - csrf_protection: { enabled: true } +This automatic protection is enabled/disabled with the ``csrf_protection`` in +the ``config/packages/framework.yaml`` file. For more information, see the +:ref:`form configuration reference `. - .. code-block:: xml +.. _form-csrf-customization: - - - +By default Symfony adds the CSRF token in a hidden field called ``_token``, but +this can be customized on a form-by-form basis:: - - - - + // ... + use App\Entity\Task; + use Symfony\Component\OptionsResolver\OptionsResolver; - .. code-block:: php + class TaskType extends AbstractType + { + // ... - // config/packages/framework.php - $container->loadFromExtension('framework', array( - 'csrf_protection' => null, - )); + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => Task::class, + // enable/disable CSRF protection for this form + 'csrf_protection' => true, + // the name of the hidden HTML field that stores the token + 'csrf_field_name' => '_token', + // an arbitrary string used to generate the value of the token + // using a different string for each form improves its security + 'csrf_token_id' => 'task_item', + )); + } + + // ... + } + +.. caution:: + + Since the token is stored in the session, a session is started automatically + as soon as you render a form with CSRF protection. + +.. caution:: + + CSRF tokens are meant to be different for every user. Beware of that when + caching pages that include forms containing CSRF tokens. For more + information, see :doc:`/http_cache/form_csrf_caching`. + +CSRF Protection in Login Forms +------------------------------ + +`Login CSRF attacks`_ can be prevented using the same technique of adding hidden +CSRF tokens into the login forms. The Security component already provides CSRF +protection, but you need to configure some options before using it. + +.. tip:: + + If you're using a :doc:`Guard Authenticator `, + you'll need to validate the CSRF token manually inside of that class. See + :ref:`guard-csrf-protection` for details. -Then, the security component needs a CSRF token provider. You can set this to -use the default provider available in the security component: +First, configure the CSRF token provider used by the form login in your security +configuration. You can set this to use the default provider available in the +security component: .. configuration-block:: @@ -107,26 +140,12 @@ use the default provider available in the security component: ), )); -The Security component can be configured further, but this is all information -it needs to be able to use CSRF in the login form. - -.. tip:: - - If you're using a :doc:`Guard Authenticator `, - you'll need to validate the CSRF token manually inside of that class. See - :ref:`guard-csrf-protection` for details. - .. _csrf-login-template: -Rendering the CSRF field ------------------------- - -Now that Security component will check for the CSRF token, you have to add -a *hidden* field to the login form containing the CSRF token. By default, -this field is named ``_csrf_token``. That hidden field must contain the CSRF -token, which can be generated by using the ``csrf_token()`` function. That -function requires a token ID, which must be set to ``authenticate`` when -using the login form: +Then, use the ``csrf_token()`` function in the Twig template to generate a CSRF +token and store it as a hidden field of the form. By default, the HTML field +must be called ``_csrf_token`` and the string used to generate the value must +be ``authenticate``: .. configuration-block:: @@ -223,5 +242,39 @@ After this, you have protected your login form against CSRF attacks. ), )); -.. _`Cross-site request forgery`: https://en.wikipedia.org/wiki/Cross-site_request_forgery -.. _`Forging Login Requests`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests +CSRF Protection in HTML Forms +----------------------------- + +It's also possible to add CSRF protection to regular HTML forms not managed by +the Symfony Form component, for example the simple forms used to delete items. +First, use the ``csrf_token()`` function in the Twig template to generate a CSRF +token and store it as a hidden field of the form: + +.. code-block:: twig + +
+ {# the argument of csrf_token() is an arbitrary value used to generate the token #} + + + +
+ +Then, get the value of the CSRF token in the controller action and use the +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::isCsrfTokenValid` +to check its validity:: + + use Symfony\Component\HttpFoundation\Request; + // ... + + public function delete(Request $request) + { + $submittedToken = $request->request->get('token'); + + // 'delete-item' is the same value used in the template to generate the token + if ($this->isCsrfTokenValid('delete-item', $submittedToken)) { + // ... do something, like deleting an object + } + } + +.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery +.. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index e3b6ff8ca6d..f6da87b0188 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -243,8 +243,7 @@ The form can look like anything, but it usually follows some conventions: .. caution:: This login form is currently not protected against CSRF attacks. Read - :doc:`/security/csrf_in_login_form` on how to protect your login - form. + :doc:`/security/csrf` on how to protect your login form. And that's it! When you submit the form, the security system will automatically check the user's credentials and either authenticate the user or send the