Obtain a verified client address in classic ASP.NET

Prefer web-server real-IP handling

Configure the web server or a supported trusted-proxy integration to verify the immediate connection source before applying a client-IP header. The NGINX real-IP guide explains the trust boundary. Use the resulting verified client address exposed by that integration; do not apply the same header again in application code.

Application fallback with an explicit trust boundary

For classic ASP.NET/ASPX, the fallback below requires Request.UserHostAddress to still be the immediate connection peer, before any real-IP rewriting. If another proxy sits between X4B and the application, configure and verify the complete trust chain at the web server instead.

Add this helper to your application code. It parses the peer and configured proxies as addresses, accepts a single valid IPv4 or IPv6 header only from a trusted peer, and otherwise returns the original peer. Match the address family reported by your server, including an explicitly listed IPv4-mapped IPv6 address when needed.

using System;
using System.Net;
using System.Net.Sockets;

public static class VerifiedClientAddress
{
    public static string Resolve(string peerIp, string forwardedIp,
        string[] trustedProxyIps)
    {
        IPAddress peer;
        if (!IPAddress.TryParse(peerIp, out peer))
            return peerIp;

        bool trusted = false;
        foreach (string configuredIp in trustedProxyIps)
        {
            IPAddress proxy;
            if (IPAddress.TryParse(configuredIp, out proxy)
                && peer.Equals(proxy))
                trusted = true;
        }

        IPAddress client;
        if (!trusted || String.IsNullOrEmpty(forwardedIp)
            || forwardedIp != forwardedIp.Trim()
            || forwardedIp.IndexOfAny(new[] { ',', '[', ']', '%' }) >= 0
            || !IPAddress.TryParse(forwardedIp, out client))
            return peerIp;

        if (client.AddressFamily == AddressFamily.InterNetwork
            && forwardedIp != client.ToString())
            return peerIp;

        return client.ToString();
    }
}

Call the helper from your request-handling code:

string peerIp = HttpContext.Current.Request.UserHostAddress;
string clientIp = VerifiedClientAddress.Resolve(
    peerIp,
    HttpContext.Current.Request.Headers["X-Real-IP"],
    new[] { "192.0.2.10", "2001:db8::10" });

Use clientIp for the verified application address and retain peerIp for auditing. Do not overwrite Request.ServerVariables["REMOTE_ADDR"]. Missing, malformed or comma-separated header values retain the original peer. If you changed Backend Real IP Header in HTTP Options, adjust the header lookup to match.

Verify the boundary

In an isolated test, confirm that a valid header from a trusted proxy is accepted, while a forged header from an untrusted peer and an invalid header from a trusted peer both retain the original peer. Check IPv4 and IPv6, and review the trust list after backend communication addresses change.

See Real IP for applicability and Microsoft's IPAddress.TryParse reference for address parsing. This example targets classic ASP.NET; ASP.NET Core applications should use their framework's trusted-proxy configuration.