当我在ZEND中添加CSRF时,为什么验证码重新加载不起作用?

时间:2013-02-26 11:05:33

标签: zend-form

当我添加以下代码时,重新加载验证码工作正常

以ZEND表格形式:

 $this->setName("login");
    $this->setMethod('post');

    $this->addElement('text', 'username', array(
    'filters'    => array('StringTrim', 'StringToLower'),
    'validators' => array(
        array('StringLength', false, array(0, 50)),
    ),
    'required'   => true,
    'label'      => 'Username:',
    ));

    $this->addElement('password', 'password', array(
    'filters'    => array('StringTrim'),
    'validators' => array(
        array('StringLength', false, array(0, 50)),
    ),
    'required'   => true,
    'label'      => 'Password:',
     ));


// Add a captcha
$this->addElement('captcha', 'captcha', array(
'label'      => 'Please enter the 5 letters displayed below:',
'required'   => true,
'captcha'    => array(
    'captcha' => 'Figlet',
    'wordLen' => 5,
    'timeout' => 300
)
 ));



  $captcha = $this->createElement('captcha', 'captcha', array(
    'required' => true,
    'captcha' => array(
        'captcha' => 'Image',
        'font' => APPLICATION_PATH . '/../public/fonts/arial.ttf',
        'fontSize' => '24',
        'wordLen' => 5,
        'height' => '50',
        'width' => '150',
        'imgDir' => APPLICATION_PATH.'/../public/captcha',
        'imgUrl' => Zend_Controller_Front::getInstance()->getBaseUrl().'/captcha',
        'dotNoiseLevel' => 50,
        'lineNoiseLevel' => 5,
    ),
    'description' => 'Refresh Captcha Image'

  ));

  $captcha->setLabel('Please type the words shown:');
  $captcha->removeDecorator("htmlTag")->removeDecorator('label');
  $captcha->addDecorator('Errors', array('class' => 'err-username', 'style' => 'display:none'));
  $captcha->addDecorator('Description', array('id' => 'refreshcaptcha'));

    $this->addElement($captcha);
 $this->getElement('captcha')->removeDecorator("htmlTag")->removeDecorator('label');

// And finally add some CSRF protection
  /*$this->addElement('hash', 'csrf', array(
'ignore' => true,
 ));*/

 $this->addElement('submit', 'login', array(
'required' => false,
'ignore'   => true,
'label'    => 'Login',
 ));

在phtml中:

    <script type="text/javascript">
    $(document).ready(function() {
        $('#refreshcaptcha').click(function() { 
            $.ajax({ 
                url: "<?php echo $this->url(array('controller' => 'auth', 'action' => 'refresh'), 'default', false) ?>", 
                dataType:'json', 
                success: function(data) { 
                    $('#contactForm img').attr('src', data.src); 
                    $('#captcha-id').attr('value', data.id); 
                }
            }); 
        }); 
    });
    </script>

    <?php
        //Default
        //$this->form->setAction($this->url());
        //echo $this->form;
    ?>

    <?php 
    $errorsMessages = $this->form->getMessages();
    //http://www.websitefactors.co.uk/zend-framework/2011/06/error-class-on-form-field-errors-using-zend-form/
    ?>
    <?php 
    foreach($this->form->getMessages() as $elemName=>$messages) {
        foreach($messages as $message) {
            $label = $this->form->getElement($elemName)->getLabel();
            echo $this->escape($label.' '.$message)."<br>" ;
        }
    }
    ?>
    <div id="contactForm">
    <form method="<?php echo $this->form->getMethod(); ?>" action="<?php echo $this->form->getAction(); ?>">
    <?php echo $this->form->username->renderViewHelper(); ?>
    <?php echo $this->form->password->renderViewHelper(); ?>
    <?php echo $this->form->captcha; ?>
    <?php //echo $this->form->csrf->renderViewHelper(); ?>
    <?php echo $this->formSubmit('submit', 'Sign in',array('class'=>'button')); ?>
    </form>
    </div>

当我点击“刷新验证图像”时,验证验证码图像而不刷新页面,它工作正常,但当我添加下面的CSRF(跨站点请求伪造)代码并重新加载验证码然后提交时,登录永远不会成功。它给了我错误:“值是必需的,不能为空”或“请输入显示的单词:验证码值错误

  $this->addElement('hash', 'csrf', array(
        'ignore' => true,
    ));

1 个答案:

答案 0 :(得分:0)

每次请求都会生成Zend_Form_Element_Hash。所以当你点击“刷新验证图像”时会发生新的请求。然后,当您提交表单时,您已经用完了请求,因此csrf检查失败,因为令牌不同步。

要解决此问题,您可能会做错事,只是将跳数增加到一些高数字。但这有助于否定你所追求的安全性。正确解决此问题的一种方法是在refresh()操作中重新初始化auth控制器中的令牌。然后,您可以发回包含此新令牌的json_encoded响应。

....
$form->captcha->initCsrfToken(); //recreate token and send it back
$responseArray['hash'] =  $form->captcha->getValue();
echo Zend_Json::encode($responseArray);

在执行ajax调用之后,您可以使用从refresh()操作中获取的内容替换该标记。例如:

var newHash = jQuery.parseJSON(data).hash;
$('#yourcsrfelement').val(newHash);