CakePHP 在 SecurityComponent 中有一个 requireSecure 函数。我在传递信用卡号等敏感信息时使用它来强制使用 SSL。
问题:
我想要一个 requireNonSecure 功能,因为我的一些页面嵌入了只能在我们的域名上播放的视频。使用 SSL 时,视频托管服务无法识别我们的域名,因此无法播放视频。
这是控制器的 beforeFilter 中的一些代码:
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中的回调
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 添加一个函数,如下所示:
在控制器中:
function beforeFilter() {
parent::beforeFilter();
// Require non secure (http) for video action
$this->requireNonSecure('video');
// ... other code here
}
在app_controller.php中:
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,则存在重定向循环的风险。
SecurityPlus 组件:
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函数:
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);
}
}
在控制器中会这样调用:
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');
}