如何CSRF保护发送到另一个页面的表单


How to CSRF secure a form that posts to another page?

我有一个关于CSRF安全性和登录表单的小问题。表单的工作方式如下:

在主布局中,视图帮助器创建一个登录表单,并在用户通过身份验证后显示一个特定于用户的菜单。

    // User menu viewhelper
public function authentication()
{
    // Check if user is authenticated or not
    $auth = Zend_Auth::getInstance();
    if(!$auth->hasIdentity())
    {
        $form = new Application_Form_Login();
        $form->setAction($this->_view->url(array('action' => 'login'), 'ucp', true));
        return $form;
    }
    else
    {
        // return user specific menu
    }
}

表单发送到包含所有用户控制面板逻辑的UcpController,例如登录/退出和显示用户特定信息。

    // loginAction in UcpController
public function loginAction()
{
    if(Zend_Auth::getInstance()->hasIdentity())
    {
        $this->_redirect('/');
        return;
    }
    $request = $this->getRequest();
    $form = new Application_Form_Login();
    if($request->isPost())
    {
        if($form->isValid($post = $request->getPost()))
        {
            // Do authentication stuff here.
        }
    }
    $this->view->form = $form;
}

遗憾的是,这样CSRF令牌无法匹配,我不知道如何解决这个问题。我遗漏了什么吗?我应该一起删除CSRF验证吗?

// The CSRF protection element as added to the login form
$this->addElement('hash', 'csrf',
    array(
        'ignore' => true
    )
);

提前感谢,非常感谢您的帮助:)

你的代码似乎是正确的,我认为问题可能是在其他地方。要调试此问题,请执行以下操作:

使用firebug检查生成的Application_Form_Login,特别是CSRF令牌,然后当您将数据发布到Zend_Debug::dump时,尝试在loginAction中使用$_SESSION$_POST数组并比较结果。您应该找到您发布的数据和会话数据之间的匹配。

您应该在发送的post变量和名为Zend_Form_Element_Hash_salt_<name-of-your-element>的会话变量之间搜索匹配,如果值匹配,则错误在其他地方,您应该转储$form->getMessages()以找到它。

正如zerkms在评论中指出的,我前面的句子是错误的。我查看了实现,发现ZF中的CSRF令牌每300秒更改一次,在此超时情况下,令牌过期不应该是您的问题。

问题解决了!我遇到了一个遇到同样问题的人。原因很奇怪:http://tinyurl.com/3fkg8bk (ZF论坛)

当它转向我时,我的图标返回一个HTTP 500代码,因为文件不存在。这显然会触发生成一个新的CSRF。我不知道为什么,但它解决了我的问题,创建一个图标,并将其上传到webroot。

感谢你至少和我一起思考!