CakePHP (все версии, которые я видел) проверяют на $_SERVER['HTTPS']
чтобы увидеть, был ли запрос выполнен поверх HTTPS вместо простого HTTP.
Я использую nginx как балансировщик нагрузки, за которым стоят серверы приложений Apache. Поскольку соединение SSL завершается на балансировщике нагрузки, $_SERVER['HTTPS']
не задан в отношении CakePHP.
Я бы хотел найти безопасный способ обнаружения 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;
для добавления флага к любым запросам между балансировщиком нагрузки и серверами back-end приложений.
Это работает отлично, но любой, кто делает прямой запрос к серверам приложений, может обмануть их, думая, что они просматривают SSL, когда это не так. Я не уверен, является ли это угрозой безопасности, но это не кажется хорошей идеей.
Это риск для безопасности? Какое лучшее решение?
Поскольку использование X-Forwarded-Proto
кажется чем-то стандартным , решение может быть хорошим патчем, который должен быть отправлен в ядро CakePHP, поэтому я думаю, что любой ответ может законно включать редактирование основных файлов.
mod_rpaf позволит вам это сделать.
Это устанавливает значение HTTPS в Apache для «on» на основе заголовков, отправленных nginx, поэтому Cake будет работать из коробки (как и любые другие приложения, запущенные в Apache).
Он также корректирует значения для REMOTE_ADDR, SERVER_PORT и HTTP_HOST.
Вот мой пример config:
<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>
Не редактируйте ядро. Если вы намерены подать патч, не полагайтесь на свой патч до тех пор, пока он не будет принят. В противном случае вы находитесь на пути к расхождению и поддерживаете свою собственную вилку CakePHP.
Как только вы определите свою точную логику реализации, вы можете использовать детектор запросов, чтобы почитать его.
например:
//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 loadbalancer; или изменить свой детектор так, чтобы он не возвращал true для запросов прямого доступа, независимо от значения заголовка X-Forwarded-Proto
– как показано в документации, вы можете использовать обратный вызов для выполнения любой логики, а не просто для проверки значений некоторой переменной среды.
Я нашел комментарий 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))); }