Hubbry Logo
X-Forwarded-ForX-Forwarded-ForMain
Open search
X-Forwarded-For
Community hub
X-Forwarded-For
logo
8 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
X-Forwarded-For
X-Forwarded-For
from Wikipedia

The X-Forwarded-For (XFF) HTTP header field is a common method for identifying the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.

The X-Forwarded-For HTTP request header was introduced by the Squid caching proxy server's developers.[citation needed]

X-Forwarded-For is also an email-header indicating that an email-message was forwarded from one or more other accounts (probably automatically).[1]

Without the use of XFF or another similar technique, any connection through the proxy would reveal only the originating IP address of the proxy server, effectively turning the proxy server into an anonymizing service, thus making the detection and prevention of abusive accesses significantly harder than if the originating IP address were available. The usefulness of XFF depends on the proxy server truthfully reporting the original host's IP address; for this reason, effective use of XFF requires knowledge of which proxies are trustworthy, for instance by looking them up in a whitelist of servers whose maintainers can be trusted.

Format

[edit]

The general format of the field is:[2]

X-Forwarded-For: client, proxy1, proxy2

where the value is a comma+space separated list of IP addresses, the left-most being the original client, and each successive proxy that passed the request adding the IP address where it received the request from. In this example, the request passed through proxy1, proxy2, and then proxy3 (not shown in the header). proxy3 appears as remote address of the request.

Examples:[3]

X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178
X-Forwarded-For: 203.0.113.195
X-Forwarded-For: 2001:db8:85a3:8d3:1319:8a2e:370:7348

Because the X-Forwarded-For header is not formally standardized, some variations to the IP address format exist. For example, some implementations[which?] include the port number of clients, or enclose IPv6 addresses in square brackets even without the port number, similar to the format in the newer Forwarded header. Examples:

X-Forwarded-For: 203.0.113.195:41237, 198.51.100.100:38523
X-Forwarded-For: [2001:db8::1a2b:3c4d]:41237, 198.51.100.100:26321
X-Forwarded-For: [2001:db8::aa:bb]

Usage

[edit]

The X-Forwarded-For header is added or edited by HTTP proxies when forwarding a request. The server appends the address of the client to an existing X-Forwarded-For header separated by a comma, or creates a new X-Forwarded-For header with the client address as the value.

Since it is easy to forge an X-Forwarded-For field the given information should be used with care. The right-most IP address is always the IP address that connects to the last proxy, which means it is the most reliable source of information. X-Forwarded-For data can be used in a forward or reverse proxy scenario. If the server is behind a trusted reverse proxy and only allows connections from that proxy, the header value can usually be assumed to be trustworthy.

Just logging the X-Forwarded-For field is not always enough as the last proxy IP address in a chain is not contained within the X-Forwarded-For field, it is in the actual IP header. A web server should log both the request's source IP address and the X-Forwarded-For field information for completeness.

Alternatives and variations

[edit]

RFC 7239 standardized a Forwarded HTTP header with similar purpose but more features compared to the X-Forwarded-For HTTP header.[4] An example of a Forwarded header's syntax:

Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43
Forwarded: for="[2001:db8::1234]"

HAProxy defines the PROXY protocol which can communicate the originating client's IP address without using the X-Forwarded-For or Forwarded header.[5] This protocol can be used on multiple transport protocols and does not require inspecting the inner protocol, so it is not limited to HTTP.

See also

[edit]

References

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
The X-Forwarded-For (XFF) HTTP request header is a for identifying the originating of a client connecting to a through an HTTP proxy or load balancer. It enables intermediaries such as proxies to preserve and forward the client's original , which would otherwise be obscured by the proxy's own address, supporting use cases like logging, , and geolocation. Although not formally specified in any RFC, XFF has become widely adopted across s and proxies, including implementations in software like and . The header's value consists of a comma-separated list of IP addresses (or IP literals), where the leftmost entry represents the original client IP, and each subsequent entry denotes an intervening proxy, ordered from the client toward the server. For example, a request might include X-Forwarded-For: 203.0.113.195, 198.51.100.178, 2001:db8:85a3::8a2e, indicating the client's IP followed by two proxies. Proxies append their incoming client's IP to the existing list (or initiate it if absent), but the header is request-only and not intended for responses. Servers like can be configured to use XFF via modules such as ngx_http_realip_module to override the apparent client address for internal processing. Despite its utility, XFF poses significant security and privacy risks, as clients or malicious proxies can spoof values to impersonate other IPs, potentially bypassing , IP bans, or access restrictions. Administrators must therefore validate and trust only segments from known, internal proxies, often discarding untrusted prefixes. As a non-standard header, its standardized successor is the Forwarded header defined in RFC 7239, although XFF remains widely used.

Overview

Definition and Purpose

The X-Forwarded-For (XFF) HTTP request header is a de-facto standard used to identify the originating of a client connecting to a through one or more HTTP proxies or load balancers. When a request passes through such intermediaries, the server would otherwise only see the IP address of the immediate proxy, obscuring the true client's origin. The header allows proxies to append the client's IP to the request chain, preserving this information for downstream processing. The primary purpose of the X-Forwarded-For header is to enable web servers and applications to access the real client for essential functions, rather than relying on the proxy's IP. This supports critical features such as accurate access records, geolocation-based content delivery, to prevent abuse, and IP-based access controls. For instance, content delivery networks (CDNs) and load balancers use it to route and personalize responses based on the client's location without compromising performance. Introduced informally in the 1990s by developers of early proxy software, including the caching proxy, the header addressed limitations in web architectures where IP spoofing and proxying made client identification unreliable. A typical XFF header value might appear as follows, representing a chain of proxies:

X-Forwarded-For: 203.0.113.195, 198.51.100.178, 192.0.2.1

X-Forwarded-For: 203.0.113.195, 198.51.100.178, 192.0.2.1

Here, 203.0.113.195 is the originating client IP, followed by the IPs of intervening proxies.

History

The X-Forwarded-For (XFF) HTTP header originated as a non-standard extension to HTTP/1.0 in the mid-1990s, introduced by the developers of the caching to preserve client IP addresses when requests passed through proxies in the growing web ecosystem. Squid's implementation addressed the limitation of proxies obscuring originating client information, appending the client's IP to a new header for forwarding to origin servers. This informal approach quickly gained traction among proxy users needing visibility into client origins without altering core HTTP standards. By the early 2000s, as content delivery networks (CDNs) and load balancers proliferated, XFF adoption expanded significantly to support distributed architectures. Early CDN providers integrated the header to track client locations for optimized routing and caching, while web servers like and began supporting it for logging and request processing. , released in 2004, included XFF handling in its proxy modules from initial stable versions, enabling seamless integration in setups. A pivotal milestone occurred in 2014 with the publication of RFC 7239, which formalized the related Forwarded header as an HTTP extension but recognized XFF's established de-facto role in proxy chains. In the cloud computing era of the 2010s, XFF's utility persisted, with AWS Elastic Load Balancing incorporating support upon its 2009 launch to expose client IPs behind load balancers. As of July 2025, documentation from MDN Web Docs continues to describe XFF as a de-facto standard without full IETF standardization, underscoring its enduring, practical dominance in web infrastructure.

Technical Specifications

Header Format

The X-Forwarded-For (XFF) header value is a comma-separated list of IP addresses that documents the chain of IP addresses from the original client through intermediate proxies to the immediate proxy forwarding the request. The leftmost IP address represents the originating client, while each subsequent address, added by the respective proxy, indicates the IP from which the request was received. For a direct connection without proxies, the value contains a single IP address, such as 203.0.113.195. In a chain with one proxy, it expands to include both, for example, 203.0.113.195, 198.51.100.178, where the second address is the proxy's IP. The format supports both IPv4 and addresses, with IPv6 literals expressed in their standard notation without enclosing brackets to distinguish them in the comma-separated sequence. An example IPv6 value for a direct client connection is 2001:db8:85a3:8d3:1319:8a2e:370:7348. Mixed chains are also valid, such as 203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348, 198.51.100.178, combining IPv4 client, IPv6 proxy, and IPv4 final proxy. While the standard de facto format specifies IP addresses only, some non-standard implementations append ports to the addresses, resulting in values like 203.0.113.195:80. In proxy chains, the convention is for each proxy to append the IP address of its connecting client to the existing header value, preserving the prior chain, rather than overwriting it entirely. If no X-Forwarded-For header exists upon receipt, the proxy initiates a new one with the connecting client's IP. The header's length is constrained by general HTTP implementation limits, typically 8 KB per header in servers like Apache HTTP Server, which can lead to truncation in chains with many proxies. Longer values may exceed these practical boundaries, causing incomplete chains to be discarded or abbreviated by the receiving server.

Parsing and Processing

In the proxy appending logic for the X-Forwarded-For (XFF) header, each intermediary proxy or load balancer appends the IP address from which it received the request to the end of the comma-separated list upon forwarding a request, thereby preserving the chain of originating addresses while identifying the sequence of intermediaries. This process begins with the originating client IP as the leftmost entry, followed by subsequent proxy IPs appended to the right, ensuring the header maintains a chronological record from client to server without overwriting prior values. Server-side extraction of the client IP from the XFF header typically involves parsing the list from right to left, skipping addresses belonging to trusted proxies (configured via IP ranges or counts), and selecting the first non-matching, valid public IP as the trusted originating client address. For instance, in configurations where the immediate proxy is trusted, the second-to-rightmost IP is often used as the client IP, while private ranges (such as 127.0.0.1 or RFC 1918 addresses like 192.168.0.0/16) are excluded to avoid internal or loopback artifacts. This right-to-left traversal aligns with implementations in servers like Nginx, where the real_ip_recursive directive enables recursive skipping of trusted addresses until a non-trusted one is found. Similarly, Apache's mod_remoteip module processes the header in right-to-left order, halting at the first untrusted IP after validating against RemoteIPTrustedProxy directives. Edge cases in XFF processing include handling malformed headers, where invalid IP formats (e.g., non-numeric strings or malformed octets) prompt servers to discard the header and fallback to the direct connection IP from the TCP socket. Non-standard setups may feature multiple XFF headers in a single request, which servers combine into a unified comma-separated list—either by concatenating split values or joining raw strings—before parsing to avoid loss of chain information. Programming examples for XFF parsing often involve splitting the header value by commas, trimming whitespace, and validating each IP against standard formats. For IPv4 validation, a common regular expression is ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$, which matches dotted-decimal notation ranging from to 255.255.255.255. The following illustrates a basic extraction routine, assuming a trusted proxy count for simplicity:

function extractClientIP(headers, trustedProxyCount) { if (!headers['X-Forwarded-For']) { return getConnectionIP(); // Fallback to direct socket IP } let ipList = headers['X-Forwarded-For'] .split(',') .map(ip => ip.trim()) .filter(ip => isValidIP(ip)); if (ipList.length === 0) { return getConnectionIP(); } // Select IP just before trusted proxies (right-to-left logic) let clientIndex = ipList.length - trustedProxyCount; return clientIndex >= 0 ? ipList[clientIndex] : ipList[0]; }

function extractClientIP(headers, trustedProxyCount) { if (!headers['X-Forwarded-For']) { return getConnectionIP(); // Fallback to direct socket IP } let ipList = headers['X-Forwarded-For'] .split(',') .map(ip => ip.trim()) .filter(ip => isValidIP(ip)); if (ipList.length === 0) { return getConnectionIP(); } // Select IP just before trusted proxies (right-to-left logic) let clientIndex = ipList.length - trustedProxyCount; return clientIndex >= 0 ? ipList[clientIndex] : ipList[0]; }

This logic, adapted from common server practices, ensures robustness by validating and filtering before selection.

Implementation and Usage

In Proxy Servers and Load Balancers

In proxy servers like Squid, the forwarded_for directive set to on causes the server to append the IP address of the connecting client to the existing X-Forwarded-For header—or create it if absent—before forwarding the HTTP request to upstream servers or neighbors. This behavior ensures that the original client IP is preserved in the chain as the request traverses the proxy. Similarly, HAProxy uses the option forwardfor directive in a backend, frontend, or defaults section to add the client IP address, appending it as a comma-separated value to any pre-existing X-Forwarded-For header in the request. Load balancers such as employ the ngx_http_proxy_module to generate and forward the header, typically via the proxy_set_header directive paired with the $proxy_add_x_forwarded_for variable, which s the connecting IP ($remote_addr) to the header's current value or initializes it if none exists. In AWS Application Load Balancers (s), the header is handled automatically in the default "" mode, where the inserts the client into the X-Forwarded-For field upon intercepting traffic, adding it to any existing without overwriting prior entries. This configuration can be adjusted via the routing.http.xff_header_processing.mode attribute to other modes like "preserve" or "remove" if needed, though remains standard for preservation. When requests pass through multiple intermediaries—such as a CDN layer followed by a load balancer and then an —each component appends the IP of the immediately preceding hop to the X-Forwarded-For header, forming a comma-separated list that reconstructs the full request path from client to destination. For example, in Cloudflare's implementation as a CDN, if no X-Forwarded-For header is present in the incoming request, it sets the header to the visitor's (matching CF-Connecting-IP); otherwise, it appends the IP of the connecting proxy to the existing list, maintaining the chain without alteration to prior values. A representative NGINX configuration snippet for enabling this in a proxy setup appears in a location block as follows:

location / { proxy_pass http://upstream_backend; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

location / { proxy_pass http://upstream_backend; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

This directive ensures the load balancer appends its connecting IP to propagate the client origin accurately downstream.

In Web Servers and Logging

In web servers, the X-Forwarded-For (XFF) header is parsed to retrieve the original client IP address, enabling accurate logging of visitor activity instead of proxy addresses. In Apache HTTP Server version 2.4 and later, the mod_remoteip module processes the XFF header to override the remote IP address, populating the %a format specifier in access logs with the client's true IP for modules like mod_log_config. This ensures logs reflect the originating user for auditing and analysis purposes. Similarly, in Microsoft Internet Information Services (IIS), advanced logging can be configured to include the XFF header as a custom field, allowing access logs to capture the client IP rather than the proxy's address. Administrators enable this via the IIS Manager by adding XFF to log definitions, which supports detailed tracking in environments like load-balanced setups. For application logic, web servers and frameworks leverage the parsed XFF value to implement IP-dependent features. In Node.js-based applications, setting app.set('trust proxy', true) configures req.ip to fallback to the leftmost IP in the XFF header when behind proxies, providing the client IP for programmatic use. This enables functionalities such as IP-based , where access controls verify user locations; bot detection, by cross-referencing IPs against known suspicious patterns; and content personalization, tailoring responses based on geolocation derived from the IP. Integration with analytics tools further utilizes XFF for precise data enrichment. In the ELK Stack (, Logstash, ), Logstash filters parse the XFF header to extract the client IP, which is then processed by the GeoIP plugin for geolocation mapping, allowing visualizations of visitor origins in dashboards. This approach ensures accurate spatial analytics from proxied traffic. For 4 in server-side tagging setups via Google Tag Manager, the client IP from XFF can be forwarded in requests to override the default, enabling correct geolocation and IP-based filtering without exposing raw visitor IPs. Parsing XFF introduces minor computational overhead due to string splitting and validation, particularly in high-traffic scenarios where frequent header processing occurs on every request. To mitigate this, implementations often recommend pre-parsing at the proxy layer or caching resolved IPs in session stores for repeated accesses, though the impact remains negligible compared to overall request handling.

Security Implications

Associated Risks

One primary security risk associated with the X-Forwarded-For (XFF) header is IP spoofing, where attackers manipulate the header's value to impersonate other clients and bypass IP-based access controls or restrictions. Since the XFF header is an HTTP request header that clients or intermediate proxies can modify, unvalidated entries allow malicious actors to insert arbitrary IP addresses, potentially granting unauthorized access to restricted resources. Recent vulnerabilities highlight the dangers of improper XFF handling. In April 2025, CVE-2025-22457 affected Connect Secure gateways, enabling remote code execution through a stack-based triggered by manipulated XFF values, which allowed unauthenticated attackers to execute arbitrary code on vulnerable devices. Similarly, a 2024 authentication bypass vulnerability (CVE-2024-47070) in Authentik's exploited invalid XFF entries, such as unparsable IP strings like "a", to circumvent policies and enable unauthorized logins. Further vulnerabilities in late 2025, such as CVE-2025-64525 and CVE-2025-63784, involved unsanitized or unvalidated X-Forwarded-* headers leading to potential server-side request forgery or open redirects. The XFF header also introduces privacy concerns by exposing the original client IP address in server logs and shared proxy environments, where this information—considered personally identifiable—can lead to data leaks if logs are improperly secured or accessed by unauthorized parties. In multi-tenant setups, such as cloud proxies, aggregated XFF data may inadvertently reveal user locations or browsing patterns, amplifying risks during breaches. Furthermore, forged XFF values can facilitate denial-of-service (DoS) amplification by misleading rate-limiting mechanisms, causing servers to throttle or block innocent third-party IPs instead of the attacker's, or by overwhelming logging systems with fabricated addresses that dilute legitimate traffic analysis. This misdirection can escalate attacks, as defenders may inadvertently penalize unrelated networks while the true source remains unmitigated.

Mitigation Strategies

To mitigate risks associated with the X-Forwarded-For (XFF) header, servers must implement trust validation by configuring them to accept and process the header only from known proxy IP addresses or ranges. In , this is achieved using the ngx_http_realip_module, where the set_real_ip_from directive specifies trusted CIDR blocks (e.g., set_real_ip_from 192.168.1.0/24;), and real_ip_header X-Forwarded-For; extracts the client IP solely from requests originating from those addresses, preventing spoofing by untrusted sources. Similarly, Apache's mod_remoteip module uses the RemoteIPHeader X-Forwarded-For directive combined with RemoteIPTrustedProxy to enforce the same validation logic. Recent best practices emphasize header sanitization and fallback mechanisms to enhance . For instance, servers should sanitize the XFF header by trusting only the rightmost (last) non-private in or resetting it entirely at the edge proxy to avoid manipulation, while falling back to the direct connection IP if validation fails. In deployments, the platform operates in an append-only mode for XFF, adding the visitor's IP to the end of the existing header without overwriting prior values, which preserves chain integrity when multiple proxies are involved. These measures, recommended in 2025 analyses, reduce exposure to injection attacks by ensuring only verifiable IP data influences logging or access controls. Effective monitoring and auditing are essential for detecting XFF-related anomalies. Administrators should conduct regular reviews of access logs to identify unusual patterns, such as unexpected IP chains or private IPs in public contexts, which may indicate spoofing attempts. Integration with web application firewalls (WAFs) like provides automated detection through custom rules that inspect the first IP in the XFF header against known proxies or block requests with malformed chains, as outlined in rulesets for open proxy abuse prevention. In multi-tenant environments, planning for XFF deprecation involves a gradual migration to standardized alternatives like the Forwarded header (RFC 7239), prioritizing trusted platform-specific mechanisms to minimize spoofing risks while maintaining compatibility. This shift, advised in cloud security guidelines, includes phased testing and documentation updates to ensure seamless transitions without disrupting IP-based policies.

Alternatives and Extensions

The X-Forwarded-Host header preserves the original Host header value from the client's request as it passes through proxies or load balancers, allowing backend servers to reconstruct the intended destination domain, such as "example.com". This is particularly useful in environments where multiple virtual hosts are served behind a single proxy IP address. The X-Forwarded-Proto header specifies the protocol used by the client to connect to the proxy or load balancer, typically "http" or "https", enabling backend applications to generate correct absolute URLs, redirects, or security checks without relying on the proxied connection's protocol. For instance, in reverse proxy setups, it ensures that applications behind an HTTPS-terminating proxy can properly enforce secure links or handle protocol-specific logic. The X-Forwarded-Port header captures the destination port from the original client request, such as 443 for , which aids in port-specific or on the backend server. Though less commonly implemented than other X-Forwarded headers, it is supported in certain load balancers like AWS Application Load Balancers to provide complete connection metadata. These headers are frequently configured together in and load balancer setups to maintain a full picture of the original request context, complementing the IP-focused X-Forwarded-For header. In , for example, administrators commonly use the proxy_set_header directive to append values like $host for X-Forwarded-Host, $scheme for X-Forwarded-Proto, and $server_port for X-Forwarded-Port, ensuring seamless across proxy chains. Similarly, Apache's mod_proxy module recognizes and forwards these headers to preserve request integrity in multi-tier architectures.

Standardized Successors

The Forwarded HTTP header, defined in RFC 7239 published in June 2014 by Andreas Petersson and Martin Nilsson, serves as a standardized successor to the non-standard X-Forwarded-For header, enabling proxies to disclose information about the original request that would otherwise be lost during proxying. This header consolidates multiple proxy-related details into a single extensible field, using a comma-separated list of semicolon-delimited parameter-value pairs, such as for for the client's or identifier, by for the proxy's identifying interface, proto for the connecting protocol, and host for the original Host header value. For example, a typical value might be Forwarded: for=198.51.100.178;proto=http;by=203.0.113.195, where for and by support IPv4, , obfuscated values like _hidden for (secrecy), or unknown for undisclosed details. Unlike X-Forwarded-For, which lacks formal structure and trust indicators, Forwarded includes built-in mechanisms for to enhance , though it still relies on operators configuring trusted proxy chains to prevent tampering. The development of the Forwarded header was motivated by key limitations in X-Forwarded-For, including its absence of , inconsistent across implementations, and lack of parameters for protocol or proxy identification, which complicated and trust verification in multi-hop proxy environments. These shortcomings prompted the IETF to create a unified extension that supports extensible parameters while addressing issues between disparate forwarded headers. In and , pseudo-headers such as :authority (replacing the Host header) and :scheme provide native equivalents for some forwarded information like the original host and protocol, potentially reducing reliance on headers like X-Forwarded-Host. However, these protocols do not inherently convey client IP addresses through the , making Forwarded or X-Forwarded-For necessary for and IP disclosure in proxy chains. Adoption of the Forwarded header has been gradual due to the entrenched use of X-Forwarded-For in legacy systems, with many implementations prioritizing the de-facto standard for compatibility. As of 2025, documentation from Developer Network recommends Forwarded as the preferred choice for new proxy and load balancer configurations, citing its and enhanced features. Modern content delivery networks (CDNs) are increasingly supporting it; for instance, Cloud's Media CDN automatically adds the Forwarded header per RFC 7239 to preserve request metadata for origins. Despite this progress, X-Forwarded-For remains prevalent in production environments, reflecting slow migration trends driven by the need to maintain interoperability with older infrastructure.

References

Add your contribution
Related Hubs
User Avatar
No comments yet.