Как правильно обрабатывать SSL, когда WP находится за обратным прокси?

Вопрос или проблема

Я использую WordPress за прокси. Функция is_ssl() в wp_includes/load.php никогда не сможет работать в такой среде, потому что $_SERVER['HTTPS'] не понимает, как браузер видит страницу. Все запросы нормализуются прокси.

Я могу заставить мой сайт работать, изменив функцию is_ssl(), но сейчас WordPress периодически “исправляет” мою поправку, когда выполняет автоматическое обновление.

Какой предпочтительный способ решения этой ситуации? В данный момент я использую версию v5.7.1 и даже не вижу способа отключить обновления. Я бы всё равно не хотел отключать обновления.

Как я могу указать WordPress, что is_ssl() всегда истинно, и сохранить это навсегда во время обновлений?

Вы не можете подключить is_ssl() для переопределения результата, и, как вы заметили, вы не можете редактировать ядро WordPress, иначе ваши изменения потеряются, если вы используете встроенные автоматические обновления.

Поэтому обычный подход – смотрите документацию WordPress – это установить $_SERVER['HTTPS'] = 'on';, что является свойством, которое тестирует is_ssl(). Добавьте следующий блок в wp-config.php (который сохраняется во время обновлений), где-то перед окончательным require_once:

if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
    $_SERVER['HTTPS'] = 'on';
}

Это проверяет, добавил ли ваш обратный прокси заголовок X-Forwarded-Proto: https к проксированному запросу, и если он сделал это, то устанавливает флаг HTTPS для WordPress, чтобы флаг SSL действительно пытался отразить исходный запрос. Плагин Really Simple SSL имеет более комплексную версию этого, которую я тоже использовал, и которая тестирует больше значений от других прокси:

// Начало исправления Really Simple SSL для балансировки нагрузки
if ((isset($_ENV["HTTPS"]) && ("on" == $_ENV["HTTPS"]))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "1") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_SSL"]) && (strpos($_SERVER["HTTP_X_FORWARDED_SSL"], "on") !== false))
  || (isset($_SERVER["HTTP_CF_VISITOR"]) && (strpos($_SERVER["HTTP_CF_VISITOR"], "https") !== false))
  || (isset($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_CLOUDFRONT_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && (strpos($_SERVER["HTTP_X_FORWARDED_PROTO"], "https") !== false))
  || (isset($_SERVER["HTTP_X_PROTO"]) && (strpos($_SERVER["HTTP_X_PROTO"], "SSL") !== false))
) {
  $_SERVER["HTTPS"] = "on";
}
// Конец Really Simple SSL

И существует альтернативный подход здесь на StackOverflow, где вы можете использовать конфигурацию Apache, чтобы установить HTTPS=1, если это проще:

<IfModule mod_setenvif.c>
  SetEnvIf X-Forwarded-Proto "^https$" HTTPS
</IfModule>

вместо редактирования wp-config.php.

Это более старая ветка, но я хочу поделиться решением.

Шаг 1: доступ к DB > wp_options > siteurl: https://domain.com

Шаг 2: доступ к DB > wp_options > home: https://domain.com

Шаг 3: редактирование /var/www/wordpress/wp-config.php >

  define('WP_SITEURL', 'https://domain.com');
  define('WP_HOME', 'https://domain.com');

и вставьте код ниже на следующей строке:

 /** Исправление для SSL за прокси **/
  $parsedUrl = parse_url(WP_HOME);
  $scheme = $parsedUrl['scheme'];
  if ($scheme == 'https') {$_SERVER['HTTPS'] = 'on';}
  else {$_SERVER['HTTPS'] = 'off';}

Другие решения (изменение wp-config.php) работают, но настоящее решение должно быть на уровне веб-сервера.

Если мы используем Apache, можно добавить это в ваш VirtualHost:

<VirtualHost *:80>
  SetEnvIf X-Forwarded-Proto "^https$" HTTPS
</VirtualHost>

Однако, если у вас традиционная настройка обратного прокси, при которой ваш сервис (wordpress/apache) всегда возвращает HTTP-трафик, а ваш обратный прокси всегда возвращает https-трафик вызывающему клиенту, более правильным решением будет добавить следующее в ваш VirtualHost:

<VirtualHost *:80>
  ServerName https://example.com
</VirtualHost>

Наличие https:// в префиксе ServerName решает проблему, и Apache автоматически всегда установит HTTPS в положение on. Разница между этим и использованием SetEnv HTTPS on заключается в том, что такая конфигурация дает другим модулям Apache информацию о вашем сайте, и они могут использовать её для правильной работы.

Например, эта ошибка (https://github.com/apache/httpd/pull/325), где поведение DirectorySlash возвращает префикс 301 перенаправление с http://, решается, когда ServerName явно установлен таким образом.

.

Ответ или решение

Обеспечение правильного использования SSL в среде WordPress, функционирующей за обратным прокси-сервером, может вызвать множество сложностей, особенно когда базовые функции такие, как is_ssl(), не работают так, как ожидается. Рассмотрим, как можно справиться с этой задачей, не изменяя ядро WordPress, что предотвращает потерю изменений при автоматических обновлениях.

Теория

Когда WordPress используется за обратным прокси, сервер, содержащий сайт, не всегда может правильно определить, была ли инициализирована защита SSL на уровне клиента. Это связано с тем, что обратный прокси может модифицировать запросы, отсеивая информацию о протоколе, которую браузер обеспечивает клиенту. Следствием этого является неспособность функции is_ssl() определить, что используется HTTPS, так как она опирается на значение 'HTTPS' в глобальном массиве $_SERVER.

Пример

Типичная ситуация: вы используете nginx или другой прокси-сервер перед Apache, где развернут WordPress. Браузер инициирует соединение через HTTPS, но, когда запрос проходит через прокси, эта информация теряется. Следовательно, WordPress не может определить, что соединение безопасное, так как значение $_SERVER['HTTPS'] не установлено в ‘on’.

Для выполнения решения этой проблемы существует подход, который заключается в использовании заголовка X-Forwarded-Proto, добавляемого прокси-сервером для указания протокола, используемого клиентом.

Применение

1. Изменения в wp-config.php

Проще всего решить проблему путем модификации файла wp-config.php, так как этот файл не затрагивается обновлениями WordPress. Вставьте следующий код до конца файла до последней строки require_once:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Этот код проверяет значение заголовка X-Forwarded-Proto, добавленного вашим прокси-сервером. Если он содержит ‘https’, переменная $_SERVER['HTTPS'] устанавливается в ‘on’, притворяясь, что соединение идет через SSL.

2. Использование plugins

Вы можете использовать плагин Really Simple SSL, который упрощает переход сайта на HTTPS, учитывая различные случаи использования прокси-серверов и их настройки.

3. Настройки на уровне веб-сервера

Если ваше приложение работает на Apache, вы можете настроить сервер, используя конфигурацию для ваших виртуальных хостов. Пример:

<VirtualHost *:80>
    ServerName example.com
    SetEnvIf X-Forwarded-Proto "https" HTTPS=on
</VirtualHost>

Такая конфигурация помогает серверу самостоятельно распознавать защищенные соединения. Обратите внимание, что использование SetEnvIf вместе с корректной конфигурацией ServerName позволяет Apache и другим модулям корректно обрабатывать информацию о протоколе.

Наконец, вы можете подумать о поддержке конфигурации прокси-сервера, чтобы он изменял заголовок на приемной стороне, чтобы WordPress понимал, что он работает через SSL. Важно убедиться, что заголовки не перезаписываются на других уровнях сети.

Приняв эти шаги, вы обеспечите корректное функционирование WordPress за обратным прокси, не вмешиваясь в ядро платформы и сохраняя стабильность даже при последующих обновлениях. Таким образом, вы можете сосредоточиться на развитии функциональности сайта, не опасаясь проблем с конфигурацией SSL.

Оцените материал
Добавить комментарий

Капча загружается...