1

我在表单的 CSRF 验证和使用使用 ZF2 存储在数据库中的会话方面遇到了一些问题。

这是我添加到 Module.php onBootstrap() 方法的代码:

// create session which is persisted in the database
        $dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
        $sessionTableGateway = new TableGateway\TableGateway('XXX.XXX', $dbAdapter);
        $sessionOptions = new DbTableGatewayOptions();
        $sessionOptions->setDataColumn('SESSION_DATA')
                       ->setIdColumn('SESSION_ID')
                       ->setModifiedColumn('SESSION_MODIFIED')
                       ->setLifetimeColumn('SESSION_LIFETIME')
                       ->setNameColumn('SESSION_NAME');
        $sessionGateway = new DbTableGateway($sessionTableGateway, $sessionOptions);
        $sessionConfig = new SessionConfig();
        $sessionConfig->setOptions(array(
            'gc_probability' => 1,
            'gc_divisor' => 1,
            'use_cookies' => true
        ));
        $storage = new SessionStorage();
        $sessionManager = new SessionManager($sessionConfig, $storage);
        $sessionManager->setSaveHandler($sessionGateway);
        $sessionManager->start(true);
        Container::setDefaultManager($sessionManager);

在表单中,我正在创建一个标准的 CSRF 元素,如下所示:

$this->add(array(
            'name' => 'csrf',
            'type' => 'Zend\Form\Element\Csrf'
        ));

加载表单后,我可以看到存储在数据库中的会话中的 CSRF 哈希:

__ZF|a:2:{s:20:"_REQUEST_ACCESS_TIME";d:1383673583.296492099761962890625;s:29:"Zend_Validator_Csrf_salt_csrf";a:1:{s:6:"EXPIRE";i:1383673883;}}FlashMessenger|C:23:"Zend\Stdlib\ArrayObject":21:{x:i:2;a:0:{};m:a:0:{}}Zend_Validator_Csrf_salt_csrf|C:23:"Zend\Stdlib\ArrayObject":72:{x:i:2;a:1:{s:4:"hash";s:32:"1ba5170385f4c2e2839766f19c3c2dbd";};m:a:0:{}

当我提交表单时,我没有收到任何错误,但是,表单的 isValid() 方法似乎失败了,看起来 CSRF 验证例程总是从存储在我的会话中获取 CSRF 令牌的空值数据库。

关于这里发生了什么的任何想法?

谢谢

4

1 回答 1

0

如果您的代码中其他地方的会话没有问题,那么这可能是表单问题,而不是数据库会话问题。确保表单中的 CSRF 输入元素...:

SomeForm.php

use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\Form\Form;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;

class SomeForm extends Form
{
    public function __construct($name = null)
    {
        parent::__construct('csrf-eg');
        $this->setAttribute('method', 'post');

        // CSRF field
        $this->add
            (
                array
                (
                    'type'          =>  'Zend\Form\Element\Csrf',
                    'name'          =>  'your_csrf',
                    'attributes'    =>  array
                                        (
                                            'type'      =>  'text',
                                            'id'        =>  'divIDforCsrfField',
                                        ),
                    'options'       =>  array
                                        (
                                            'csrf_options'  =>  array
                                                                (
                                                                    'timeout'   =>  600
                                                                )
                                        ),
                )
            );
    }
}

实际上为 CSRF 字段附加了一个过滤器和验证:

SomeFormFilter.php

namespace Some\Form;

use Zend\Form\Element;
use Zend\Form\Fieldset;
use Zend\InputFilter\Input;
use Zend\InputFilter\InputFilter;
use Zend\Validator;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;

class SomeFormFilter implements InputFilterAwareInterface
{
    public $your_csrf;

    protected $inputFilter;

    public function exchangeArray($data){...}

    public function setInputFilter(InputFilterInterface $inputFilter){...}

    public function getInputFilter()
    {
        if (!$this->inputFilter){

        $inputFilter    =   new InputFilter();
        $factory        =   new InputFactory();

        // CSRF field
        $inputFilter->add
        (
            $factory->createInput
            (
                array
                (
                    'name'       => 'your_csrf',
                    'required'   =>  true,
                    'validators' =>  array
                    (
                        array
                        (
                            'name'    =>  'Csrf',
                            'options' =>  array
                            (
                               'messages'  =>  array
                               (
                                   Validator\Csrf::NOT_SAME => 'Your CSRF validation msg',
                               ),
                            ),
                        ),
                   )
               )
          );

        $this->inputFilter  =   $inputFilter;
        }

    return $this->inputFilter;
    }
}

要将您的 csrf 验证消息放入您的操作中:

$SomeForm        =   new SomeForm();
$SomeFormValues  =   $this->getRequest()->getPost();
$SomeForm->setData($SomeFormValues);

$SomeFormFilter  =   new SomeFormFilter();
$SomeForm->setInputFilter($SomeFormFilter->getInputFilter());

if ($SomeForm->isValid($SomeFormValues))
{
    $validatedData      =   $SomeForm->getData();
}
else
{
    $SomeFormMessages   =   $SomeForm->getMessages();
}

$viewModel      =   new ViewModel
                    (
                        array
                        (
                            'SomeFormMessages'    =>  $SomeFormMessages,
                        )
                    );

return $viewModel;
于 2014-01-22T04:32:37.117 回答