Nginx realip module breaks Laravel's TrustProxies middleware
Affected Docker Images
serversideup/php:beta-8.3-fpm-nginx
However, I think the issue may affects all images because the nginx configuration entry causing this has not changed for years.
Docker Labels of the affected images
{"org.opencontainers.image.authors":"Jay Rogers (@jaydrogers)","org.opencontainers.image.description":"Supercharge your PHP experience. Based off the offical PHP images, serversideup/php includes pre-configured PHP extensions and settings for enhanced performance and security. Optimized for Laravel and WordPress.","org.opencontainers.image.documentation":"https://serversideup.net/open-source/docker-php/docs/","org.opencontainers.image.licenses":"GPL-3.0-or-later","org.opencontainers.image.source":"https://github.com/serversideup/docker-php","org.opencontainers.image.title":"serversideup/php ()","org.opencontainers.image.url":"https://serversideup.net/open-source/docker-php/","org.opencontainers.image.vendor":"ServerSideUp","org.opencontainers.image.version":"git-12a4960-7869052174"}
Current Behavior
Since this is a docker image, and the docker network is not configured to host mode most of the time, the nginx in docker will see every requests from the docker network (for example, from 172.22.0.1) and consider it as trusted. After that, PHP's $_SERVER['REMOTE_ADDR'] will be set to the CF-Connecting-IP header. This breaks Laravel's trusted proxies feature (it is actually from Symfony, see symfony/symfony#26006). Some possible results are:
- Breaks Laravel's URL generation if TLS is configured outside this docker image (for example,
[user] --https-- [caddy] --http-- [nginx in docker]). All generated URLs will be withhttp://rather thanhttps://. - If the website is not using Cloudflare, users may send a fake IP with
CF-Connecting-IPheader to spoof PHP.
Expected Behavior
If nginx needs to trust the docker network, CF-Connecting-IP should not be used.
Steps To Reproduce
-
Create a Laravel project and run it with
serversideup/php:beta-8.3-fpm-nginx -
Create a route to the function:
function test()
{
echo json_encode(
[
...collect($_SERVER)->only([
'HTTP_CF_CONNECTING_IP',
'HTTP_X_FORWARDED_FOR',
'REMOTE_ADDR',
]),
'isFromTrustedProxy' => request()->isFromTrustedProxy(),
],
JSON_PRETTY_PRINT,
);
die;
}
-
curl http://localhost:9000/test
{
"REMOTE_ADDR": "172.22.0.1",
"isFromTrustedProxy": true
}
-
curl --header "CF-Connecting-IP: 1.2.3.4" http://localhost:9000/test
{
"HTTP_CF_CONNECTING_IP": "1.2.3.4",
"REMOTE_ADDR": "1.2.3.4",
"isFromTrustedProxy": false
}
Host Operating System
Debian 12
Docker Version
Client: Docker Engine - Community
Version: 25.0.3
API version: 1.44
Go version: go1.21.6
Git commit: 4debf41
Built: Tue Feb 6 21:14:25 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 25.0.3
API version: 1.44 (minimum version 1.24)
Go version: go1.21.6
Git commit: f417435
Built: Tue Feb 6 21:14:25 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.28
GitCommit: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Anything else?
No response