mirror of
https://github.com/screentinker/screentinker.git
synced 2026-05-15 07:32:23 -06:00
Express's req.ip was resolving to a Cloudflare edge address (e.g. 172.70.x.x) for any request fronted by Cloudflare, because trust proxy was set to '1' — that trusts the immediate hop, which IS Cloudflare. All activity_log rows from API paths captured the proxy, not the client. The WebSocket path was unaffected and recorded the real IP. Two layers of defense: 1. trust proxy now lists Cloudflare's published v4 + v6 ranges plus loopback / linklocal / uniquelocal (config/cloudflareIps.js). With this list req.ip resolves to the original client when fronted by CF, and X-Forwarded-For from any non-trusted source is ignored — so the value can't be spoofed. 2. New getClientIp(req) helper in services/activity.js prefers the CF-Connecting-IP header but only honors it when the immediate TCP peer is itself a trusted address. Same gate as trust proxy, so a visitor who hits the origin directly with a forged header is logged at their real address. Routed all five activity-log call sites (auth login success/failure, admin password reset, generic activityLogger middleware, and the in-memory rate-limiter key) through the helper. Logging-only change. No schema changes. Existing rows are not modified — fix applies to new entries going forward. Verified locally: - Bare loopback hit logs 127.0.0.1 (not a proxy address). - Helper unit cases including an untrusted peer (203.0.113.7) sending a forged CF-Connecting-IP correctly fall back to the real peer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
1.1 KiB
JavaScript
40 lines
1.1 KiB
JavaScript
// Cloudflare published edge IP ranges.
|
|
// Source: https://www.cloudflare.com/ips-v4 and https://www.cloudflare.com/ips-v6
|
|
// Snapshot: 2026-05-07. Update by hand when Cloudflare publishes a new list.
|
|
const cloudflareIpv4 = [
|
|
'173.245.48.0/20',
|
|
'103.21.244.0/22',
|
|
'103.22.200.0/22',
|
|
'103.31.4.0/22',
|
|
'141.101.64.0/18',
|
|
'108.162.192.0/18',
|
|
'190.93.240.0/20',
|
|
'188.114.96.0/20',
|
|
'197.234.240.0/22',
|
|
'198.41.128.0/17',
|
|
'162.158.0.0/15',
|
|
'104.16.0.0/13',
|
|
'104.24.0.0/14',
|
|
'172.64.0.0/13',
|
|
'131.0.72.0/22',
|
|
];
|
|
|
|
const cloudflareIpv6 = [
|
|
'2400:cb00::/32',
|
|
'2606:4700::/32',
|
|
'2803:f800::/32',
|
|
'2405:b500::/32',
|
|
'2405:8100::/32',
|
|
'2a06:98c0::/29',
|
|
'2c0f:f248::/32',
|
|
];
|
|
|
|
const cloudflareIps = [...cloudflareIpv4, ...cloudflareIpv6];
|
|
|
|
// What Express's trust-proxy and our CF-Connecting-IP gate both honor.
|
|
// 'loopback', 'linklocal', 'uniquelocal' keep local dev and any LAN reverse
|
|
// proxy working without further config.
|
|
const trustedProxies = ['loopback', 'linklocal', 'uniquelocal', ...cloudflareIps];
|
|
|
|
module.exports = { cloudflareIpv4, cloudflareIpv6, cloudflareIps, trustedProxies };
|