web-dev-qa-db-fra.com

Comment configurer correctement settings.php pour utiliser le proxy inverse et la terminaison SSL

Dans settings.php, il y a la section "Reverse Proxy Configuration". Il suggère des paramètres à ajouter lorsque vous utilisez un proxy inverse et une terminaison SSL.

Nginx écoute sur le port 443, ajoute les en-têtes et passe ensuite à Apache Httpd sur le port localhost 80. Voici le Nginx comme décrit:

    server {
        listen 443 ssl http2;

        server_name example.com;
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;

        location / {
            proxy_pass http://127.0.0.1:80;
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header Host $Host;
        }
}

Avec ces paramètres/en-têtes à l'esprit, quelle sélection serait correcte dans la "Configuration du proxy inverse"; dans settings.php?

 * Reverse Proxy Configuration:
 *
 * Reverse proxy servers are often used to enhance the performance
 * of heavily visited sites and may also provide other site caching,
 * security, or encryption benefits. In an environment where Drupal
 * is behind a reverse proxy, the real IP address of the client should
 * be determined such that the correct client IP address is available
 * to Drupal's logging, statistics, and access management systems. In
 * the most simple scenario, the proxy server will add an
 * X-Forwarded-For header to the request that contains the client IP
 * address. However, HTTP headers are vulnerable to spoofing, where a
 * malicious client could bypass restrictions by setting the
 * X-Forwarded-For header directly. Therefore, Drupal's proxy
 * configuration requires the IP addresses of all remote proxies to be
 * specified in $settings['reverse_proxy_addresses'] to work correctly.
 *
 * Enable this setting to get Drupal to determine the client IP from
 * the X-Forwarded-For header (or $settings['reverse_proxy_header'] if set).
 * If you are unsure about this setting, do not have a reverse proxy,
 * or Drupal operates in a shared hosting environment, this setting
 * should remain commented out.
 *
 * In order for this setting to be used you must specify every possible
 * reverse proxy IP address in $settings['reverse_proxy_addresses'].
 * If a complete list of reverse proxies is not available in your
 * environment (for example, if you use a CDN) you may set the
 * $_SERVER['REMOTE_ADDR'] variable directly in settings.php.
 * Be aware, however, that it is likely that this would allow IP
 * address spoofing unless more advanced precautions are taken.
 */
# $settings['reverse_proxy'] = TRUE;

/**
 * Specify every reverse proxy IP address in your environment.
 * This setting is required if $settings['reverse_proxy'] is TRUE.
 */
# $settings['reverse_proxy_addresses'] = array('a.b.c.d', ...);

/**
 * Set this value if your proxy server sends the client IP in a header
 * other than X-Forwarded-For.
 */
# $settings['reverse_proxy_header'] = 'X_CLUSTER_CLIENT_IP';

/**
 * Set this value if your proxy server sends the client protocol in a header
 * other than X-Forwarded-Proto.
 */
# $settings['reverse_proxy_proto_header'] = 'X_FORWARDED_PROTO';

/**
 * Set this value if your proxy server sends the client protocol in a header
 * other than X-Forwarded-Host.
 */
# $settings['reverse_proxy_Host_header'] = 'X_FORWARDED_Host';

/**
 * Set this value if your proxy server sends the client protocol in a header
 * other than X-Forwarded-Port.
 */
# $settings['reverse_proxy_port_header'] = 'X_FORWARDED_PORT';

/**
 * Set this value if your proxy server sends the client protocol in a header
 * other than Forwarded.
 */
# $settings['reverse_proxy_forwarded_header'] = 'FORWARDED';

Tester les paramètres de l'hôte qui finissent par être passés à PHP (7) en ajoutant ce qui suit au bas du fichier setting.php:

print '<pre>'; 
print_r($_SERVER);
print '</pre>';

Les en-têtes ajoutés par Nginx sont transmis mais l'URI du serveur est toujours défini sur [SCRIPT_URI] => http://www.example.com/ plutôt que [SCRIPT_URI] => https://www.example.com/.

Quel serait le proxy inverse correct Drupal dans settings.php pour que les choses fonctionnent correctement?

6
Taylor Taff

Cela devrait fonctionner pour les deux Drupal 7 et 8. C'est en fait le global.inc pour l'un de mes Aegir set-ups, qui obtient injecté dans tous les sites hébergés 'settings.php des dossiers.

<?php # global settings.php

/**
 * Tell all Drupal sites that we're running behind an HTTPS proxy.
 */

// Drupal 7 configuration.
if (explode('.', VERSION)[0] == 7) {
  $conf['reverse_proxy'] = TRUE;
  $conf['reverse_proxy_addresses'] = ['1.2.3.4', ...];

  // Force the protocol provided by the proxy. This isn't always done
  // automatically in Drupal 7. Otherwise, you'll get mixed content warnings
  // and/or some assets will be blocked by the browser.
  if (php_sapi_name() != 'cli') {
    if (isset($_SERVER['SITE_SUBDIR']) && isset($_SERVER['RAW_Host'])) {
      // Handle subdirectory mode.
      $base_url = $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['RAW_Host'] . '/' . $_SERVER['SITE_SUBDIR'];
    }
    else {
      $base_url = $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['SERVER_NAME'];
    }
  }
}
// Drupal 8 configuration.
else {
  $settings['reverse_proxy'] = TRUE;
  $settings['reverse_proxy_addresses'] = ['1.2.3.4', ...];
}
4
colan

Cela fait partie de settings.php que j'utilise sur Google Cloud:

// Force secure connection if the request wasn't made from CLI.
if (PHP_SAPI !== 'cli') {
  // Fix HTTPS if we're behind load balancer.
  if (getenv('HTTPS') !== 'on' && getenv('HTTP_X_FORWARDED_PROTO') === 'https') {
    $_SERVER['HTTPS'] = 'on';
  }

  // Perform redirect to secure connection if needed.
  if ($_SERVER['HTTPS'] !== 'on') {
    header('HTTP/1.0 301 Moved Permanently');
    header('Location: https://'. getenv('HTTP_Host') . getenv('REQUEST_URI'));
    exit;
  }
}

//...

// Enable LB headers, if applicable.
if (getenv('HTTP_VIA')) {
  $settings['reverse_proxy'] = TRUE;
  $settings['reverse_proxy_addresses'] = ['0.0.0.0']; // LB IP
}

Jetez un œil à https://www.drupal.org/node/2492389 et voyez également les en-têtes que vous recevez afin de pouvoir ajuster les valeurs de Drupal en conséquence.

1
user21641

Drupal 8

Appliquez les paramètres suivants dans le site settings.php fichier:

$settings['reverse_proxy'] = TRUE;
$settings['reverse_proxy_addresses'] = [@$_SERVER['REMOTE_ADDR']]

Cela devrait fonctionner pour CDN où les adresses IP sont dynamiques.

Ceci est expliqué dans le commentaire suivant:

 * In order for this setting to be used you must specify every possible
 * reverse proxy IP address in $settings['reverse_proxy_addresses'].
 * If a complete list of reverse proxies is not available in your
 * environment (for example, if you use a CDN) you may set the
 * $_SERVER['REMOTE_ADDR'] variable directly in settings.php.
 * Be aware, however, that it is likely that this would allow IP
 * address spoofing unless more advanced precautions are taken

Drupal 7

$conf['reverse_proxy'] = TRUE;
$conf['reverse_proxy_addresses'] = [@$_SERVER['REMOTE_ADDR']];

Voir également:

0
kenorb

Si vous avez une adresse IP de proxy inverse dynamique, mais que vous savez qu'elle doit se trouver sur le réseau interne (par exemple, le cluster kubernetes) pour valider le remote_addr est d'abord interne, vous pouvez utiliser quelque chose comme ça dans settings.php (D8):

/**
 * Helper function to check
 * if IP address is internal network
 * @param string $ip - IP address to test
 * @return boolean - false if private/internal IP
 */
function is_public_ip($ip) {
  return (bool)filter_var(
    $ip,
    FILTER_VALIDATE_IP,
    FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
  );
}

// Set reverse proxy config for correct client IP lookup (uses env var check)
if (getenv('DRUPAL_REVERSE_PROXY')) {
  $settings['reverse_proxy'] = TRUE;
  // Init address list, no overwrite
  $settings['reverse_proxy_addresses'] = $settings['reverse_proxy_addresses'] ?? [];
  // Get dynamic forwarded for or remote IP for proxy config
  // Check x-forwarded-for
  if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $forwarded_for_ips = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
    foreach ($forwarded_for_ips as $forwarded_for_ip) {
      // Not already added and is not public ip (is internal ip)
      if (!in_array($forwarded_for_ip, $settings['reverse_proxy_addresses']) && !is_public_ip($forwarded_for_ip)) {
        $settings['reverse_proxy_addresses'][] = $forwarded_for_ip;
      }
    }
  }
  // Check remote_addr to add as well just in case not added above
  if (!empty($_SERVER['REMOTE_ADDR']) && !in_array($_SERVER['REMOTE_ADDR'], $settings['reverse_proxy_addresses'])) {
    // Ensure is internal IP
    if (!is_public_ip($_SERVER['REMOTE_ADDR'])) {
      $settings['reverse_proxy_addresses'][] = $_SERVER['REMOTE_ADDR'];
    }
  }
  // No reverse_proxy for this case, as proxy address is required, use default
  if (empty($settings['reverse_proxy_addresses'])) {
    $settings['reverse_proxy'] = FALSE;
  }
}
0
David Thomas

J'ai utilisé l'excellente solution de @colan comme base, et modifié 2 lignes de sorte qu'il n'est pas nécessaire de définir manuellement les adresses_proxy_inverse.

J'ai utilisé cette solution avec grand succès pour un site assis derrière un proxy inverse nginx à terminaison SSL dans kubernetes (nginx-ingress)

/**
 * Tell all Drupal sites that we're running behind an HTTPS proxy.
 */

// Drupal 7 configuration.
if (explode('.', VERSION)[0] == 7) {
  $conf['reverse_proxy'] = TRUE;
  $conf['reverse_proxy_addresses'] = array($_SERVER['REMOTE_ADDR']);

  // Force the protocol provided by the proxy. This isn't always done
  // automatically in Drupal 7. Otherwise, you'll get mixed content warnings
  // and/or some assets will be blocked by the browser.
  if (php_sapi_name() != 'cli') {
    $base_url = $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['SERVER_NAME'];
  }
}
// Drupal 8 configuration.
else {
  $settings['reverse_proxy'] = TRUE;
  $settings['reverse_proxy_addresses'] = array($_SERVER['REMOTE_ADDR']);
}

Avertissement: (Merci à @DavidStinemetze)

Bien que cette solution résout un problème unique de pouvoir servir un site derrière un CDN ou un service avec des IP imprévisibles, il est probable que cette méthode permette l'usurpation d'adresse IP à moins que des précautions plus avancées ne soient prises. prenez ces précautions pour éviter l'usurpation

Depuis settings.php par défaut:

 * In order for this setting to be used you must specify every possible
 * reverse proxy IP address in $settings['reverse_proxy_addresses'].
 * If a complete list of reverse proxies is not available in your
 * environment (for example, if you use a CDN) you may set the
 * $_SERVER['REMOTE_ADDR'] variable directly in settings.php.
 * Be aware, however, that it is likely that this would allow IP
 * address spoofing unless more advanced precautions are taken.
0
yosefrow