我在表单的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令牌的空值存储在数据库中。
关于这里发生了什么的任何想法?
由于
答案 0 :(得分:0)
如果您的代码中的其他会话没有问题,那么这可能是表单问题而不是数据库会话问题。确保表单中的CSRF输入元素......:
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字段:
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;