|
1 | 1 | .. index::
|
2 |
| - single: Security; CSRF Protection in the Login Form |
| 2 | + single: CSRF; CSRF protection |
3 | 3 |
|
4 |
| -Using CSRF Protection in the Login Form |
5 |
| -======================================= |
| 4 | +How to Implement CSRF Protection |
| 5 | +================================ |
6 | 6 |
|
7 |
| -When using a login form, you should make sure that you are protected against CSRF |
8 |
| -(`Cross-site request forgery`_). The Security component already has built-in support |
9 |
| -for CSRF. In this article you'll learn how you can use it in your login form. |
| 7 | +CSRF - or `Cross-site request forgery`_ - is a method by which a malicious |
| 8 | +user attempts to make your legitimate users unknowingly submit data that |
| 9 | +they don't intend to submit. |
10 | 10 |
|
11 |
| -.. note:: |
| 11 | +CSRF protection works by adding a hidden field to your form that contains a |
| 12 | +value that only you and your user know. This ensures that the user - not some |
| 13 | +other entity - is submitting the given data. |
12 | 14 |
|
13 |
| - Login CSRF attacks are a bit less well-known. See `Forging Login Requests`_ |
14 |
| - if you're curious about more details. |
| 15 | +Before enabling the CSRF protection, install the CSRF support in your project |
| 16 | +(which in turn requires installing the Symfony Form component): |
15 | 17 |
|
16 |
| -Configuring CSRF Protection |
17 |
| ---------------------------- |
| 18 | +.. code-block:: terminal |
18 | 19 |
|
19 |
| -First, make sure that the CSRF protection is enabled in the main configuration |
20 |
| -file: |
| 20 | + $ composer require security-csrf form |
21 | 21 |
|
22 |
| -.. configuration-block:: |
| 22 | +CSRF Protection in Symfony Forms |
| 23 | +-------------------------------- |
23 | 24 |
|
24 |
| - .. code-block:: yaml |
| 25 | +Forms created with the Symfony Form component include CSRF tokens by default |
| 26 | +and Symfony checks them automatically, so you don't have to anything to be |
| 27 | +protected against CSRF attacks. |
25 | 28 |
|
26 |
| - # config/packages/framework.yaml |
27 |
| - framework: |
28 |
| - # ... |
29 |
| - csrf_protection: { enabled: true } |
| 29 | +This automatic protection is enabled/disabled with the ``csrf_protection`` in |
| 30 | +the ``config/packages/framework.yaml`` file. For more information, see the |
| 31 | +:ref:`form configuration reference <reference-framework-form>`. |
30 | 32 |
|
31 |
| - .. code-block:: xml |
| 33 | +.. _form-csrf-customization: |
32 | 34 |
|
33 |
| - <!-- config/packages/framework.xml --> |
34 |
| - <?xml version="1.0" encoding="UTF-8" ?> |
35 |
| - <container xmlns="http://symfony.com/schema/dic/services" |
36 |
| - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
37 |
| - xmlns:framework="http://symfony.com/schema/dic/symfony" |
38 |
| - xsi:schemaLocation="http://symfony.com/schema/dic/services |
39 |
| - http://symfony.com/schema/dic/services/services-1.0.xsd |
40 |
| - http://symfony.com/schema/dic/symfony |
41 |
| - http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> |
| 35 | +By default Symfony adds the CSRF token in a hidden field called ``_token``, but |
| 36 | +this can be customized on a form-by-form basis:: |
42 | 37 |
|
43 |
| - <framework:config> |
44 |
| - <framework:csrf-protection enabled="true" /> |
45 |
| - </framework:config> |
46 |
| - </container> |
| 38 | + // ... |
| 39 | + use App\Entity\Task; |
| 40 | + use Symfony\Component\OptionsResolver\OptionsResolver; |
47 | 41 |
|
48 |
| - .. code-block:: php |
| 42 | + class TaskType extends AbstractType |
| 43 | + { |
| 44 | + // ... |
49 | 45 |
|
50 |
| - // config/packages/framework.php |
51 |
| - $container->loadFromExtension('framework', array( |
52 |
| - 'csrf_protection' => null, |
53 |
| - )); |
| 46 | + public function configureOptions(OptionsResolver $resolver) |
| 47 | + { |
| 48 | + $resolver->setDefaults(array( |
| 49 | + 'data_class' => Task::class, |
| 50 | + // enable/disable CSRF protection for this form |
| 51 | + 'csrf_protection' => true, |
| 52 | + // the name of the hidden HTML field that stores the token |
| 53 | + 'csrf_field_name' => '_token', |
| 54 | + // an arbitrary string used to generate the value of the token |
| 55 | + // using a different string for each form improves its security |
| 56 | + 'csrf_token_id' => 'task_item', |
| 57 | + )); |
| 58 | + } |
| 59 | + |
| 60 | + // ... |
| 61 | + } |
| 62 | + |
| 63 | +.. caution:: |
| 64 | + |
| 65 | + Since the token is stored in the session, a session is started automatically |
| 66 | + as soon as you render a form with CSRF protection. |
| 67 | + |
| 68 | +.. caution:: |
| 69 | + |
| 70 | + CSRF tokens are meant to be different for every user. Beware of that when |
| 71 | + caching pages that include forms containing CSRF tokens. For more |
| 72 | + information, see :doc:`/http_cache/form_csrf_caching`. |
| 73 | + |
| 74 | +CSRF Protection in Login Forms |
| 75 | +------------------------------ |
| 76 | + |
| 77 | +`Login CSRF attacks`_ can be prevented using the same technique of adding hidden |
| 78 | +CSRF tokens into the login forms. The Security component already provides CSRF |
| 79 | +protection, but you need to configure some options before using it. |
| 80 | + |
| 81 | +.. tip:: |
| 82 | + |
| 83 | + If you're using a :doc:`Guard Authenticator </security/guard_authentication>`, |
| 84 | + you'll need to validate the CSRF token manually inside of that class. See |
| 85 | + :ref:`guard-csrf-protection` for details. |
54 | 86 |
|
55 |
| -Then, the security component needs a CSRF token provider. You can set this to |
56 |
| -use the default provider available in the security component: |
| 87 | +First, configure the CSRF token provider used by the form login in your security |
| 88 | +configuration. You can set this to use the default provider available in the |
| 89 | +security component: |
57 | 90 |
|
58 | 91 | .. configuration-block::
|
59 | 92 |
|
@@ -107,26 +140,12 @@ use the default provider available in the security component:
|
107 | 140 | ),
|
108 | 141 | ));
|
109 | 142 |
|
110 |
| -The Security component can be configured further, but this is all information |
111 |
| -it needs to be able to use CSRF in the login form. |
112 |
| - |
113 |
| -.. tip:: |
114 |
| - |
115 |
| - If you're using a :doc:`Guard Authenticator </security/guard_authentication>`, |
116 |
| - you'll need to validate the CSRF token manually inside of that class. See |
117 |
| - :ref:`guard-csrf-protection` for details. |
118 |
| - |
119 | 143 | .. _csrf-login-template:
|
120 | 144 |
|
121 |
| -Rendering the CSRF field |
122 |
| ------------------------- |
123 |
| - |
124 |
| -Now that Security component will check for the CSRF token, you have to add |
125 |
| -a *hidden* field to the login form containing the CSRF token. By default, |
126 |
| -this field is named ``_csrf_token``. That hidden field must contain the CSRF |
127 |
| -token, which can be generated by using the ``csrf_token()`` function. That |
128 |
| -function requires a token ID, which must be set to ``authenticate`` when |
129 |
| -using the login form: |
| 145 | +Then, use the ``csrf_token()`` function in the Twig template to generate a CSRF |
| 146 | +token and store it as a hidden field of the form. By default, the HTML field |
| 147 | +must be called ``_csrf_token`` and the string used to generate the value must |
| 148 | +be ``authenticate``: |
130 | 149 |
|
131 | 150 | .. configuration-block::
|
132 | 151 |
|
@@ -223,5 +242,39 @@ After this, you have protected your login form against CSRF attacks.
|
223 | 242 | ),
|
224 | 243 | ));
|
225 | 244 |
|
226 |
| -.. _`Cross-site request forgery`: https://en.wikipedia.org/wiki/Cross-site_request_forgery |
227 |
| -.. _`Forging Login Requests`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests |
| 245 | +CSRF Protection in HTML Forms |
| 246 | +----------------------------- |
| 247 | + |
| 248 | +It's also possible to add CSRF protection to regular HTML forms not managed by |
| 249 | +the Symfony Form component, for example the simple forms used to delete items. |
| 250 | +First, use the ``csrf_token()`` function in the Twig template to generate a CSRF |
| 251 | +token and store it as a hidden field of the form: |
| 252 | + |
| 253 | +.. code-block:: twig |
| 254 | +
|
| 255 | + <form action="{{ url('admin_post_delete', { id: post.id }) }}" method="post"> |
| 256 | + {# the argument of csrf_token() is an arbitrary value used to generate the token #} |
| 257 | + <input type="hidden" name="token" value="{{ csrf_token('delete-item') }}" /> |
| 258 | +
|
| 259 | + <button type="submit">Delete item</button> |
| 260 | + </form> |
| 261 | +
|
| 262 | +Then, get the value of the CSRF token in the controller action and use the |
| 263 | +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::isCsrfTokenValid` |
| 264 | +to check its validity:: |
| 265 | + |
| 266 | + use Symfony\Component\HttpFoundation\Request; |
| 267 | + // ... |
| 268 | + |
| 269 | + public function delete(Request $request) |
| 270 | + { |
| 271 | + $submittedToken = $request->request->get('token'); |
| 272 | + |
| 273 | + // 'delete-item' is the same value used in the template to generate the token |
| 274 | + if ($this->isCsrfTokenValid('delete-item', $submittedToken)) { |
| 275 | + // ... do something, like deleting an object |
| 276 | + } |
| 277 | + } |
| 278 | + |
| 279 | +.. _`Cross-site request forgery`: http://en.wikipedia.org/wiki/Cross-site_request_forgery |
| 280 | +.. _`Login CSRF attacks`: https://en.wikipedia.org/wiki/Cross-site_request_forgery#Forging_login_requests |
0 commit comments