APIGeoIP.RU

Платформа IP-аналитики и антифрода

How to correctly detect user IP address

Why REMOTE_ADDR is often wrong

When your app is behind Cloudflare, Nginx, ALB, or ingress, REMOTE_ADDR frequently contains proxy address. For antifraud this produces incorrect geo and risk scoring.

Safe extraction order

  1. Define trusted proxy addresses.
  2. If request is not from trusted proxy, use REMOTE_ADDR.
  3. If request is from trusted proxy, read CF-Connecting-IP, then X-Real-IP, then first valid IP from X-Forwarded-For.
  4. Validate every candidate IP.
  5. Log both selected IP and source header for audit.

Nginx example

set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;

Node.js

function getClientIp(req, trusted) {
  const remote = req.socket?.remoteAddress || "";
  if (!trusted.has(remote)) return remote;
  const cf = req.header("cf-connecting-ip");
  if (cf && net.isIP(cf)) return cf;
  const xr = req.header("x-real-ip");
  if (xr && net.isIP(xr)) return xr;
  const xff = req.header("x-forwarded-for") || "";
  for (const part of xff.split(",").map(x => x.trim())) {
    if (net.isIP(part)) return part;
  }
  return remote;
}

Python

def get_client_ip(request, trusted_proxies):
    remote = request.client.host if request.client else ""
    if remote not in trusted_proxies:
        return remote
    for header in ["cf-connecting-ip", "x-real-ip"]:
        value = request.headers.get(header, "")
        if is_valid_ip(value):
            return value
    for part in request.headers.get("x-forwarded-for", "").split(","):
        ip = part.strip()
        if is_valid_ip(ip):
            return ip
    return remote

PHP

function get_client_ip(array $server, array $trusted): string {
    $remote = (string)($server["REMOTE_ADDR"] ?? "");
    if (!in_array($remote, $trusted, true)) return $remote;
    $cf = trim((string)($server["HTTP_CF_CONNECTING_IP"] ?? ""));
    if (filter_var($cf, FILTER_VALIDATE_IP)) return $cf;
    $xr = trim((string)($server["HTTP_X_REAL_IP"] ?? ""));
    if (filter_var($xr, FILTER_VALIDATE_IP)) return $xr;
    foreach (array_map("trim", explode(",", (string)($server["HTTP_X_FORWARDED_FOR"] ?? ""))) as $part) {
        if (filter_var($part, FILTER_VALIDATE_IP)) return $part;
    }
    return $remote;
}

Checklist

  • Application is not directly accessible from public internet.
  • Trusted proxy list is maintained and monitored.
  • Invalid or private addresses are filtered according to policy.
  • Unit and integration tests cover header combinations.

API call

GET /api/?ip=203.0.113.42&user_id=uid_v1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Authorization: Bearer YOUR_API_KEY

Связаться с нами

Telegram: @apigeoip