与CakePHP中的requireSecure相反

Opposite of requireSecure in CakePHP

CakePHP在SecurityComponent中具有requireSecure函数。在传递敏感信息(例如信用卡号)时,我使用它来强制使用SSL。

问题:

  • 有requireNonSecure函数吗?
  • 如果没有requireNonSecure函数,是否可以在不修改原始文件的情况下将功能扩展/添加到CakePHP的核心文件中?

我需要requireNonSecure函数,因为我的某些页面上嵌入了只能在我们的域名上播放的视频。使用SSL时,视频托管服务无法识别我们的域名,也无法播放视频。

这是控制器的beforeFilter中的一些代码:

1
2
3
4
5
6
7
8
9
function beforeFilter() {
    parent::beforeFilter();

    $this->Security->validatePost = false; // disable CSRF protection
    $this->Security->blackHoleCallback = 'forceSSL';
    $this->Security->requireSecure('pay', 'index');

    $this->Auth->allow('index');
}

这是app_controller.php

中的回调

1
2
3
4
5
6
7
8
function forceSSL() {
    $redirect = '';
    if (!empty($this->params['url']['redirect'])) {
        $redirect = '?redirect=' . $this->params['url']['redirect'];
    }

    $this->redirect('https://' . rtrim(env('SERVER_NAME'), '/') . $this->here . $redirect);
}

一个解决方案是将一个函数附加到beforeFilter上,如下所示:

在控制器中:

1
2
3
4
5
6
7
8
9
function beforeFilter() {
    parent::beforeFilter();

    // Require non secure (http) for video action
    $this->requireNonSecure('video');

    // ... other code here

}

在app_controller.php中:

1
2
3
4
5
6
7
8
9
10
function requireNonSecure() {
    $requireNonSecure = array_map('strtolower', func_get_args());

    if (in_array(strtolower($this->action), $requireNonSecure) || $requireNonSecure == array('*')) {
        if ($this->RequestHandler->isSSL()) {
            $this->redirect('http://' . rtrim(env('SERVER_NAME'), '/') . $this->here);
            return;
        }
    }
}

此解决方案添加到SecurityComponent。它应该可以工作,但是如果同时设置了requireSecure和requireNonSecure,则存在重定向循环的风险。

SecurityPlusComponent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class SecurityPlusComponent extends SecurityComponent {

    /**
     * List of actions that do not require an SSL-secured connection
     *
     * @var array
     * @access public
     * @see SecurityPlusComponent::requireNonSecure()
     */
    var $requireSecure = array();

    /**
     * Component startup. All security checking happens here.
     *
     * @param object $controller Instantiating controller
     * @access public
     */
        function startup(&$controller) {
            $this->_action = strtolower($controller->action);
            $this->_methodsRequired($controller);
            $this->_secureRequired($controller);
            $this->_nonSecureRequired($controller);
            $this->_authRequired($controller);
            $this->_loginRequired($controller);

            $isPost = ($this->RequestHandler->isPost() || $this->RequestHandler->isPut());
            $isRequestAction = (
                !isset($controller->params['requested']) ||
                $controller->params['requested'] != 1
            );

            if ($isPost && $isRequestAction && $this->validatePost) {
                if ($this->_validatePost($controller) === false) {
                    if (!$this->blackHole($controller, 'auth')) {
                        return null;
                    }
                }
            }
            $this->_generateToken($controller);
        }

    function requireNonSecure() {
        $this->_requireMethod('NonSecure', func_get_args());
    }

    /**
     * Check if access requires non secure connection (http)
     *
     * @param object $controller Instantiating controller
     * @return bool true if secure connection required
     * @access protected
     */
    function _nonSecureRequired(&$controller) {
        if (is_array($this->requireNonSecure) && !empty($this->requireNonSecure)) {
            $requireNonSecure = array_map('strtolower', $this->requireNonSecure);

            if (in_array($this->_action, $requireNonSecure) || $this->requireNonSecure == array('*')) {
                if ($this->RequestHandler->isSSL()) {
                    if (!$this->blackHole($controller, 'nonSecure')) {
                        return null;
                    }
                }
            }
        }
        return true;
    }
}

已修改的app_controller forceSSL函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function securityBlackhole($type) {
    $redirect = '';
    if (!empty($this->params['url']['redirect'])) {
        $redirect = '?redirect=' . $this->params['url']['redirect'];
    }

    // Force http (non-SSL)
    if($type == 'nonSecure') {
        $this->redirect('http://' . rtrim(env('SERVER_NAME'), '/') . $this->here . $redirect);

    // Force https (SSL)
    } else {
        $this->redirect('https://' . rtrim(env('SERVER_NAME'), '/') . $this->here . $redirect);
    }
}

将在控制器中这样调用:

1
2
3
4
5
6
7
8
9
10
function beforeFilter() {
    parent::beforeFilter();

    $this->SecurityPlus->validatePost = false; // disable CSRF protection
    $this->SecurityPlus->blackHoleCallback = 'securityBlackhole';
    $this->SecurityPlus->requireSecure('pay', 'index');
    $this->SecurityPlus->requireNonSecure('video');

    $this->Auth->allow('index');
}