CakePHP安全组件漏洞登录(data[_Token][key]字段未生成)



当我尝试登录时,请求被Security组件阻塞。我怎样才能让它正常工作?

我有一个简单的登录表单

  <div class="container container-login">
    <h2><?php echo __('Login'); ?></h2>
    <div class="wrap-form-signin">
    <?php
    echo $this->Form->create('User', array('action' => 'login', 'class' => 'form-signin'));
    echo $this->Form->input('username', array('label' => '', 'placeholder' => __('Email')));
    echo $this->Form->input('password', array('label' => '', 'placeholder' => __('Password')));
    echo $this->Form->submit(__('Login'));
    echo $this->Form->end();
    ?>
    </div>
</div>

控制器的动作如下:

public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                return $this->redirect($this->Auth->redirectUrl());             
            } else {
                $this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
            }
        }
}

Security组分包含在AppController

public $components = array('Security', ... );

在error.log中我得到:

2013-03-29 13:40:58 Error: [BadRequestException] The request has been black-holed
Request URL: /users/login
Stack Trace:
#0 C:wampwwwcdxlibCakeControllerComponentSecurityComponent.php(234): SecurityComponent->blackHole(Object(UsersController), 'auth')
#1 [internal function]: SecurityComponent->startup(Object(UsersController))
#2 C:wampwwwcdxlibCakeUtilityObjectCollection.php(131): call_user_func_array(Array, Array)
#3 [internal function]: ObjectCollection->trigger(Object(CakeEvent))
#4 C:wampwwwcdxlibCakeEventCakeEventManager.php(247): call_user_func(Array, Object(CakeEvent))
#5 C:wampwwwcdxlibCakeControllerController.php(670): CakeEventManager->dispatch(Object(CakeEvent))
#6 C:wampwwwcdxlibCakeRoutingDispatcher.php(183): Controller->startupProcess()
#7 C:wampwwwcdxlibCakeRoutingDispatcher.php(161): Dispatcher->_invoke(Object(UsersController), Object(CakeRequest), Object(CakeResponse))
#8 C:wampwwwcdxappwebrootindex.php(92): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse))
#9 {main}

我怎样才能找到是什么使我的请求进入黑洞?

当我尝试使用自定义黑洞处理程序时,错误类型是auth。但这是我能得到的所有信息

我的CakePHP版本是2.3.1

编辑:在没有Security组件的情况下,登录可以正常工作。添加到AppController后,无法正常登录

EDIT2:我没有任何data[_Token][key]字段的形式

EDIT3解决方案:我的团队中有人重写了HTMLHelper类,它遗漏了_tags数组中的"hiddenblock",这导致丢失了_Token字段。有关详细信息,请参阅我和thaJeztah的回答以及下面的评论

您以什么顺序添加组件?安全组件应该放在其他在startup():

中处理表单数据的组件的之前。

"如果你正在使用安全组件的表单保护功能和其他在startup()回调中处理表单数据的组件,请确保在$components数组中将安全组件置于这些组件之前。"

安全

因为AuthComponent 处理startup()内部的表单数据,我认为这是适用的,所以要确保SecurityComponent 在你的$components数组 AuthComponent之前;

public $components = array(
    'Security',
    'Session',
    'Auth' => array(
        // auth component settings
    )
);

更新

OP发布的"最终"答案清楚地表明这个问题不可能被回答。结果是,团队中有人修改了HtmlHelper,导致输出'hidden'块,因此输出CSRF令牌。

在正常情况下,你不应该修改CakePHP框架文件本身。CakePHP提供了一些方法来覆盖它的功能(包括helper),而不需要修改CakePHP的"核心"文件。

为什么修改CakePHP文件不好

以汽车为例。如果某机械师不喜欢设计并决定"交换"刹车和加速踏板怎么办?

当然,如果你知道这个修改,汽车仍然能够驾驶。然而,如果没有这些重要的信息,任何其他驱动程序肯定会崩溃(并且想知道刚才发生了什么!?)

如果框架的默认行为不适合你的需要,扩展那些类。不要修改框架文件本身(除非真的没有其他选择)。如果对框架的修改是绝对必要的,请务必与团队讨论,并就所做的更改编写文档。

请记住,如果不将相同的修改应用到更新的版本,则无法将框架更新到新版本。同样,如果更改没有记录,有人可能会更新CakePHP并破坏您的修改。

另外,如果您覆盖或修改CakePHP,请确保覆盖与CakePHP的默认行为兼容,并且CakePHP的单元测试仍然正确运行(或为修改创建新的单元测试)

在CakePHP中使用'自定义'帮助器

如果您需要自定义CakePHP helper(或其他组件),有各种选项可以这样做,而无需修改CakePHP文件;

1。扩展Helper

class AwesomeHtmlHelper extends HtmlHelper {
    /**
     * enhanced tableHeaders method, outputs tableHeaders in a 'thead' tag
     *
     * {@inheritdoc}
     */
    public function tableHeaders(array $names, array $trOptions = null, array $thOptions = null)
    {
        $output = parent::tableHeaders($names, $trOptions, $thOptions);
        return '<thead>' . $output . '</thead>';
    }
}

然后,按常规方式使用Helper:

echo $this->AwesomeHtml->tableHeaders(array('Date', 'Title', 'Active'));

2。"插入式"替换-使用别名(CakePHP> 2.3)

从CakePHP 2.3开始,可以为Helper使用别名。此功能可用于(例如)在您的应用程序中存在两个具有相同名称的helper(例如Plugin.HtmlHelper)的情况。

同样,这允许您用自己的Helper重写CakePHP Helper。查看这里的文档:使用和配置helper

请注意,这将在应用程序中

的所有地方重写Helper !
public $helpers = array(
    'Html' => array(
        'className' => 'AwesomeHtml'
    )
);

现在,$this->Html实际上指的是视图中的AwesomeHtmlHelper:

echo $this->eHtml->tableHeaders(array('Date', 'Title', 'Active'));

将输出您的'增强'表头

编辑:

return $this->Html->useTag('hiddenblock', $out);

行,这是一个团队成员对HtmlHelper的修改,我不知道,阻止了_Token输入在页面上打印。主要问题仍然存在,那就是表单中缺少data[_Token][key]输入,我必须添加


我终于发现问题是什么了。由于FormHelper类中可能存在错误,因此没有_Token字段。我必须编辑secure方法,看起来像这样:
public function secure($fields = array()) {
    if (!isset($this->request['_Token']) || 
            empty($this->request['_Token'])) {
        return;
    }
    $locked = array();
    $unlockedFields = $this->_unlockedFields;
    foreach ($fields as $key => $value) {
        if (!is_int($key)) {
            $locked[$key] = $value;
            unset($fields[$key]);
        }
    }
    sort($unlockedFields, SORT_STRING);
    sort($fields, SORT_STRING);
    ksort($locked, SORT_STRING);
    $fields += $locked;
    $locked = implode(array_keys($locked), '|');
    $unlocked = implode($unlockedFields, '|');
    $fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
    $out = $this->hidden('_Token.fields', array(
        'value' => urlencode($fields . ':' . $locked),
        'id' => 'TokenFields' . mt_rand()
    ));
    $out .= $this->hidden('_Token.unlocked', array(
        'value' => urlencode($unlocked),
        'id' => 'TokenUnlocked' . mt_rand()
    ));
    return $this->Html->useTag('hiddenblock', $out);
}

这个方法返回一个空字符串。因此,不返回useTag的结果,而是返回$out

我必须做的另一件事是添加data[_Token][key]字段。最后,该方法看起来像这样:

public function secure($fields = array()) {
        if (!isset($this->request['_Token']) || 
                empty($this->request['_Token'])) {
            return;
        }
        $locked = array();
        $unlockedFields = $this->_unlockedFields;
        foreach ($fields as $key => $value) {
            if (!is_int($key)) {
                $locked[$key] = $value;
                unset($fields[$key]);
            }
        }
        sort($unlockedFields, SORT_STRING);
        sort($fields, SORT_STRING);
        ksort($locked, SORT_STRING);
        $fields += $locked;
        $locked = implode(array_keys($locked), '|');
        $unlocked = implode($unlockedFields, '|');
        $fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
        $key = $this->request['_Token']['key'];
        $out = $this->hidden('_Token.fields', array(
            'value' => urlencode($fields . ':' . $locked),
            'id' => 'TokenFields' . mt_rand()
        ));
        $out .= $this->hidden('_Token.key', array(
            'value' => $key,
            'id' => 'TokenKey' . mt_rand()
        ));
        $out .= $this->hidden('_Token.unlocked', array(
            'value' => urlencode($unlocked),
            'id' => 'TokenUnlocked' . mt_rand()
        ));
        return $out;
        //return $this->Html->useTag('hiddenblock', $out);
    }

这是很难测试与您提供的信息,但我会尝试改变形式创建调用:echo $this->Form->create('User', array('url' => array('controller' => 'users', 'action' => 'login'), 'class' => 'form-signin'));

auth类型的错误指示表单验证错误,或控制器/动作不匹配错误。如果显示表单的页面不是/users/login,则可能发生这种情况,因为使用安全组件时跨控制器通信是黑洞。希望能有所帮助

编辑:验证错误也可能指向您没有为Auth组件定义username的事实,检查cookbook

回答,因为我无法评论。您是否尝试过向Security组件添加回调,看看它究竟生成了什么?

看:http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#handling-blackhole-callbacks

您打算使用Security组件做什么?你想要阻止什么?

您是否尝试使用会话令牌而不是每个表单令牌?http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html csrf保护

public $components = array(
    'Security' => array(
        'csrfUseOnce' => false
    )
);

我有同样的问题与用户登录表单从登录。并在另一个视图中使用它作为元素,并通过使用$this-> form ->end()关闭表单来解决这个问题,否则它将不会添加来自令牌....的隐藏输入

最新更新