在登录表单上禁用 CSRF 令牌

Posted

技术标签:

【中文标题】在登录表单上禁用 CSRF 令牌【英文标题】:Disable CSRF token on login form 【发布时间】:2013-02-22 13:29:36 【问题描述】:

我正在使用 Symfony2.0 和 FOSUserBundle,并希望在我的登录表单上禁用 csrf 令牌。

我已在我的网站的 config.yml 中全局禁用 csrf 保护:

framework:
    csrf_protection:
        enabled:        false

这很好,我的表单中没有添加 csrf 字段。 但是,这不适用于登录表单。仅在此表单上,如果我未在表单中包含以下令牌,则会收到“无效的 CSRF 令牌”错误:

<input type="hidden" name="_csrf_token" value=" csrf_token " />

如何禁用登录表单上的 CSRF 令牌?

【问题讨论】:

你为什么要这么做? 因为我的客户希望无论用户在登录页面上停留多长时间都可以验证登录表单。此外,我个人认为这个特定网站不需要 CSRF 保护。 【参考方案1】:

您可以通过在其选项数组中设置'csrf_protection' =&gt; false 来禁用表单类中的 CSRF 保护:

class LoginType extends AbstractType

    // ...

    public function getDefaultOptions(array $options)
    
        return array(
            'data_class'      => 'Acme\UserBundle\Entity\User',
            'csrf_protection' => false
        );
    

    // ...

 

如果您使用 FormBuilder 而不是 AbstractType 类来创建表单,您可以将选项数组作为createFormBuilder() 的第二个参数传递,如下所示:

$form = $this->createFormBuilder($users, array('csrf_protection' => false))
        ->add( ... )
        ->getForm();

【讨论】:

问题是我没有这样的 LoginType 类。我是否应该扩展 Symfony2 LoginType 类以将 csrf_protection 属性设置为 false?没有更简单的方法吗? 是的,它帮助我意识到我必须查看 FOSUserBundle 的 SecurityController 才能将 csrf 设置为 false。我发布了自己的答案,但提供了有关如何进行的更多详细信息。 +1 你应该提到你正在使用 FOSUserBundle。 或者如果你在第四个参数中使用 createNamedBuilder() 方法: $form = $this->get('form.factory')->createNamedBuilder('', 'form', null , 数组('csrf_protection' => false));【参考方案2】:

如果您只是转到您的 security.yml 文件并从 form_login 指令中删除 csrf_provider,则不需要更新操作类或任何东西。

【讨论】:

【参考方案3】:

如果您使用 FOSUserBundle,并且希望仅在登录表单上禁用 CSRF 保护,则需要执行几个步骤。

步骤 1) 创建您自己的用户包和安全控制器文件

为了覆盖 FOSUserBundle 中内置的 SecurityController,您必须首先创建自己的用户包。

所以,创建一个名为 app/src/YourApp/UserBundle/Controller/SecurityController.php 的文件 您应该扩展原始的 SecurityController 类,并复制 loginAction 方法

use FOS\UserBundle\Controller\SecurityController as SecurityControllerOrig;
class SecurityController extends SecurityControllerOrig

   public function loginAction(Request $request)
   
   

在 loginAction 方法中,注释掉或删除这些行:

$csrfToken = $this->container->has('form.csrf_provider')
        ? $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate')
        : null;

然后确保 CSRF 令牌没有传递给视图:

return $this->renderLogin(array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => false,
    ));

步骤 2) 在 Symfony 的防火墙 (security.yml) 中禁用 CSRF 检查

确保注释掉 security.yml: 中现有的“csrf_provider:”行:

firewalls:
        main:
            pattern: ^/
            form_login:
                provider: fos_userbundle
                #csrf_provider: form.csrf_provider

步骤 3) 覆盖 FOSUserBundle 的安全控制器 (routing.yml) 的路由

在 routing.yml 中,注释掉这些行:

fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    options:
        expose: true

在注释掉的行下面添加这些行:

#Over-ride the SecurityController of the FOSUserBundle:
fos_user_security_login:
  path: /login
  defaults:   _controller: YourAppUserBundle:Security:login 
  methods:  [GET]
  options:
    expose: true

fos_user_security_check:
  path: /login_check
  defaults:   _controller: FOSUserBundle:Security:check 
  methods:  [POST]
  options:
    expose: true

fos_user_security_logout:
  path: /logout
  defaults:   _controller: FOSUserBundle:Security:logout 
  methods:  [GET]
  options:
    expose: true

注意 1:我只要求它使用自定义 SecurityController 中的 loginAction 方法。其他两个方法转到父类(不确定是否有区别)。

注意 2:您需要“expose: true”部分!否则,你会从 fos js 路由包中得到一个 javascript 错误。

应该这样做!

【讨论】:

【参考方案4】:

我必须override FOSUserBundle's SecurityControllerloginAction 登录表单被实例化。

我换了:

$csrfToken = $this->container->get('form.csrf_provider')->generateCsrfToken('authenticate');

return $this->container->get('templating')->renderResponse('FOSUserBundle:Security:login.html.'.$this->container->getParameter('fos_user.template.engine'), array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => $csrfToken,
    ));

与:

return $this->container->get('templating')->renderResponse('FOSUserBundle:Security:login.html.'.$this->container->getParameter('fos_user.template.engine'), array(
        'last_username' => $lastUsername,
        'error'         => $error,
        'csrf_token' => false,
    ));

【讨论】:

以上是关于在登录表单上禁用 CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章

如何将 CSRF 令牌添加到登录表单?

Symfony 5 登录表单操作返回无效的 CSRF 令牌

在 ajax 提交时禁用 symfony 2 csrf 令牌保护

SPA 使用的经过身份验证的 Rest API:如何获取用于登录和注册表单的 CSRF 令牌?

如何将 csrf 令牌添加到 html 表单?

直接访问登录表单时未设置会话 cookie,导致 CSRF 令牌无效