settings.php is too late to set $_SERVER['REMOTE_ADDR'] using a CDN's client IP header

Created on 12 July 2021, over 3 years ago
Updated 12 September 2024, 4 months ago

Problem/Motivation

D7 had the ability to nominate an alternative HTTP header from which to extract the client IP e.g. several CDNs add a True-Client-IP header or similar:

https://git.drupalcode.org/project/drupal/-/blob/7.81/sites/default/defa...

D8/9 instead recommend this:

https://git.drupalcode.org/project/drupal/-/blob/9.2.1/sites/default/def...

 * 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.

However, the Symfony Request has already been initialised by the time that settings.php is parsed, so it's too late to change the REMOTE_ADDR as the Request has its own copy of the relevant values from the _SERVER superglobal, from which it extracts the client IP.

Therefore, following the instructions in settings.php does not work.

Steps to reproduce

Assign a test value to $_SERVER['REMOTE_ADDR'] variable directly in settings.php per the instructions.

Observe that this value is not in the Request's server property, and will not be returned by e.g.

\Drupal::requestStack()->getCurrentRequest()->getClientIp();

(This module can be useful for debugging proxy headers etc..: https://www.drupal.org/project/trusted_proxy_headers_debug β†’ ).

I believe this is because (from index.php):

$kernel = new DrupalKernel('prod', $autoloader);

$request = Request::createFromGlobals();   <== the Request hoovers up values from $_SERVER
$response = $kernel->handle($request);     <== the Drupal Kernel parses settings.php here
$response->send();

$kernel->terminate($request, $response);

Proposed resolution

I'm not yet sure how a site should be configured to derive the Client IP from a value supplied by a CDN if the headers don't fit within what Symfony supports (e.g. FORWARDED / X-Forwarded-For etc..).

Remaining tasks

Figure out a solution.

User interface changes

n/a

API changes

?

Data model changes

n/a

Release notes snippet

tbc

πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
Request processingΒ  β†’

Last updated 7 days ago

No maintainer
Created by

πŸ‡¬πŸ‡§United Kingdom mcdruid πŸ‡¬πŸ‡§πŸ‡ͺπŸ‡Ί

Live updates comments and jobs are added and updated live.

Missing content requested by

πŸ‡¦πŸ‡ΊAustralia dpi
12 months ago
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024