> Symfony中文手册 > 使用CSRF保护登录表单

使用CSRF保护登录表单

当使用登录表单时,你应该确保针对CSRF (Cross-site request forgery) 进行了防护。Security组件已经内置了对CSRF的支持。在本文中,你将学习如何在登录表单使用它。

登录过程的CSRF攻击不怎么出名。如果你对此好奇,可参考 伪造登录请求。

配置CSRF防护 ¶

首先,配置Security组件,令CSRF防护可用。Security组件需要一个 CSRF token provider。你可以把这个值设为Security组件中的默认provider:

1
2
3
4
5
6
7
8
9
10
# app/config/security.yml
security:
    # ...

    firewalls:
        secured_area:
            # ...
            form_login:
                # ...
                csrf_token_generator: security.csrf.token_manager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- app/config/security.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<srv:container xmlns="Http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <config>
        <!-- ... -->
 
        <firewall name="secured_area">
            <!-- ... -->
            <form-login csrf-token-generator="security.csrf.token_manager" />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'secured_area' => array(
            // ...
            'form_login' => array(
                // ...
                'csrf_token_generator' => 'security.csrf.token_manager',
            ),
        ),
    ),
));

Security组件还可以被进一步配置,但是在登录表单使用CSRF时的全部信息都在这里了。

输出CSRF字段 ¶

现在,Security组件将要检查CSRF token,你需要在登录表单中添加一个隐藏的CSRF token字段。默认时,字段的名称是 _csrf_token。该隐藏字段必须要包含CSRF token,它可通过 csrf_token 函数生成。此函数需要一个token ID,当使用此登录表单时必须将其设为 authenticate

1
2
3
4
5
6
7
8
9
10
11
12
{# src/AppBundle/Resources/views/Security/login.HTML.twig #}
 
{# ... #}
<form action="{{ path('login') }}" method="post">
    {# ... the login fields / 表单登录的字段 #}
 
    <input type="hidden" name="_csrf_token"
        value="{{ csrf_token('authenticate') }}"
    >
 
    <button type="submit">login</button>
</form>
1
2
3
4
5
6
7
8
9
10
11
12
<!-- src/AppBundle/Resources/views/Security/login.html.php -->
 
<!-- ... -->
<form action="<?php echo $view['router']->path('login') ?>" method="post">
    <!-- ... the login fields -->
 
    <input type="hidden" name="_csrf_token"
        value="<?php echo $view['form']->csrfToken('authenticate') ?>"
    >
 
    <button type="submit">login</button>
</form>

此后,你已经可以针对CSRF攻击来保护你的表单了。

通过设置配置文件中的 csrf_parameter 你可以改变字段名称。而改变 token ID 则需要设置 csrf_token_id

1
2
3
4
5
6
7
8
9
10
11
# app/config/security.yml
security:
    # ...

    firewalls:
        secured_area:
            # ...
            form_login:
                # ...
                csrf_parameter: _csrf_security_token
                csrf_token_id: a_private_string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- app/config/security.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<srv:container xmlns="http://symfony.com/schema/dic/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:srv="http://symfony.com/schema/dic/services"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd">
 
    <config>
        <!-- ... -->
 
        <firewall name="secured_area">
            <!-- ... -->
            <form-login csrf-parameter="_csrf_security_token"
                csrf-token-id="a_private_string"
            />
        </firewall>
    </config>
</srv:container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// app/config/security.php
$container->loadFromExtension('security', array(
    // ...
 
    'firewalls' => array(
        'secured_area' => array(
            // ...
            'form_login' => array(
                // ...
                'csrf_parameter' => '_csrf_security_token',
                'csrf_token_id'     => 'a_private_string'
            ),
        ),
    ),
));