如何在nginx反向代理后面的CakePHP中安全地检测SSL?

时间:2013-01-13 14:38:36

标签: php cakephp ssl nginx reverse-proxy

CakePHP(我见过的所有版本)检查$_SERVER['HTTPS']以查看是否通过HTTPS而不是普通HTTP发出请求。

我正在使用nginx作为负载均衡器,其后面是Apache应用服务器。由于SSL连接在负载均衡器处终止,因此就CakePHP而言,$_SERVER['HTTPS']未设置。

我想找到一种在应用服务器上检测HTTPS的安全方法。

到目前为止,我已将其放入CakePHP配置中:

$request_headers = getallheaders();
if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) || ( isset($request_headers['X-Forwarded-Proto']) && $request_headers['X-Forwarded-Proto'] == 'https' ) ) {

    $ssl = true;

    // overwrite environment vars (ugly) since CakePHP won't honour X-Forwarded-Proto
    $_SERVER['HTTPS'] = 'on';
    $_ENV['HTTPS'] = 'on';

} else {
    $ssl = false;
}

然后在nginx配置中,我使用proxy_set_header X-Forwarded-Proto https;将标志添加到负载均衡器和后端应用程序服务器之间的任何请求。

这种方法非常好,但任何向应用服务器发出直接请求的人都可能会欺骗他们认为他们正在浏览SSL而不是。我不确定这是否存在安全风险,但这似乎不是一个好主意。

是安全隐患吗?什么是更好的解决方案?

由于使用X-Forwarded-Proto似乎是something of a standard,解决方案可能是提交给CakePHP核心的一个很好的补丁,因此我认为任何答案都可以合法地涉及编辑核心文件。

3 个答案:

答案 0 :(得分:3)

添加请求检测器

不要编辑核心。如果您的目的是提交补丁,请不要依赖您的补丁,直到 之后才接受补丁 - 否则您就会走上分歧并维持自己的CakePHP分支。

确定完确的实施逻辑后,您可以使用request detector来兑现它。

例如:

//AppController::beforeFilter
public function beforeFilter() {
    $this->request->addDetector('ssl', array(
        'env' => 'HTTP_X_FORWARDED_PROTO',
        'value' => 'https'
    ));
}

在此之后,您的自定义标头将被cake正确识别为ssl请求。

请注意,$_SERVER全局的键被标准化为所有大写和下划线分隔,即:

$ curl --header "X-Forwarded-Proto:https" http:://yoursite.com

将填充$_SERVER['HTTP_X_FORWARDED_PROTO'] - 因此这是检查的关键。

帐户(安全)

是的,这是你应该照顾的事情 - 要么直接禁用 访问您的网络服务器,这样只有通过负载均衡器的IP才会响应;或者修改您的探测器,使其对于直接访问请求不会返回true 无论X-Forwarded-Proto标头的值如何 - 如文档中所示,您可以使用回调来执行所需的任何逻辑,而不是简单地测试某些环境变量的值。

答案 1 :(得分:2)

mod_rpaf会让你这样做。

这会根据nginx发送的标头将Apache中的HTTPS值设置为“on”,这样Cake就可以开箱即用(以及在Apache中运行的任何其他应用程序)。

它还会更正REMOTE_ADDR,SERVER_PORT和HTTP_HOST的值。

这是我的示例配置:

<IfModule mod_rpaf.c>
    RPAF_Enable       On
    RPAF_ProxyIPs     127.0.0.1 10.0.0.0/24
    RPAF_SetHostName  On
    RPAF_SetHTTPS     On
    RPAF_SetPort      On
</IfModule>

# If mod_rewrite redirects then we lose the HTTPS status to REDIRECT_HTTPS.
# This resets it back. This happens with Cake's front controller
<IfModule setenvif_module>
    SetEnvIf REDIRECT_HTTPS on HTTPS=on
</IfModule>

答案 2 :(得分:1)

我发现了AD7six的评论 - 覆盖了redirect()函数 - 在我的SSL设置中非常有用,因为我的应用程序有一些重定向到http。

我刚刚将以下内容添加到AppController.php,因此重定向功能始终使用https:

function redirect($url, $status = NULL, $exit = true) {
    return parent::redirect(str_replace('http://', 'https://', Router::url($url, true)));
}