public class XForwardedRequestWrapperFactory extends AbstractRequestWrapperFactory
Most of the design of this Servlet Filter is a port of mod_remoteip, this servlet filter replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a proxy or a load balancer via a request headers (e.g. "X-Forwarded-For").
Another feature of this servlet filter is to replace the apparent scheme (http/https) and server port with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").
This wrapper proceeds as follows:
If the incoming request.getRemoteAddr()
matches the servlet filter's list of
internal proxies :
$remoteIPHeader
(default value
x-forwarded-for
). Values are processed in right-to-left order.$protocolHeader
(e.g.
x-forwarded-for
) equals to the value of protocolHeaderHttpsValue
configuration parameter (default https
) then request.isSecure = true
,
request.scheme = https
and request.serverPort = 443
. Note that 443 can
be overwritten with the $httpsServerPort
configuration parameter.Configuration parameters:
XForwardedFilter property | Description | Equivalent mod_remoteip directive | Format | Default Value |
---|---|---|---|---|
remoteIPHeader | Name of the Http Header read by this servlet filter that holds the list of traversed IP addresses starting from the requesting client | RemoteIPHeader | Compliant http header name | x-forwarded-for |
allowedInternalProxies | List of internal proxies ip adress. If they appear in the remoteIpHeader value,
they will be trusted and will not appear in the proxiesHeader value |
RemoteIPInternalProxy | Comma delimited list of regular expressions (in the syntax supported by the
Pattern library) |
10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\d{1,3}\.\d{1,3},
172\\.(?:1[6-9]|2\\d|3[0-1]).\\d{1,3}.\\d{1,3}, 169\.254\.\d{1,3}\.\d{1,3},
127\.\d{1,3}\.\d{1,3}\.\d{1,3} By default, 10/8, 192.168/16, 172.16/12, 169.254/16 and 127/8 are allowed |
proxiesHeader | Name of the http header created by this servlet filter to hold the list of proxies that have
been processed in the incoming remoteIPHeader |
RemoteIPProxiesHeader | Compliant http header name | x-forwarded-by |
trustedProxies | List of trusted proxies ip adress. If they appear in the remoteIpHeader value,
they will be trusted and will appear in the proxiesHeader value |
RemoteIPTrustedProxy | Comma delimited list of regular expressions (in the syntax supported by the
Pattern library) |
|
protocolHeader | Name of the http header read by this servlet filter that holds the flag that this request | N/A | Compliant http header name like X-Forwarded-Proto , X-Forwarded-Ssl
or Front-End-Https |
null |
protocolHeaderHttpsValue | Value of the protocolHeader to indicate that it is an Https request |
N/A | String like https or ON |
https |
httpServerPort | Value returned by ServletRequest.getServerPort() when the protocolHeader
indicates http protocol |
N/A | integer | 80 |
httpsServerPort | Value returned by ServletRequest.getServerPort() when the protocolHeader
indicates https protocol |
N/A | integer | 443 |
Regular expression vs. IP address blocks: mod_remoteip
allows to
use address blocks (e.g. 192.168/16
) to configure RemoteIPInternalProxy
and RemoteIPTrustedProxy
; as the JVM doesnt have a library similar to apr_ipsubnet_test.
Sample with internal proxies
XForwardedFilter configuration:
<filter>
<filter-name>XForwardedFilter</filter-name>
<filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class>
<init-param>
<param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value>
</init-param>
<init-param>
<param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value>
</init-param>
<init-param>
<param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value>
</init-param>
<init-param>
<param-name>protocolHeader</param-name><param-value>x-forwarded-proto</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XForwardedFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Request values:
property | Value Before XForwardedFilter | Value After XForwardedFilter |
---|---|---|
request.remoteAddr | 192.168.0.10 | 140.211.11.130 |
request.header['x-forwarded-for'] | 140.211.11.130, 192.168.0.10 | null |
request.header['x-forwarded-by'] | null | null |
request.header['x-forwarded-proto'] | https | https |
request.scheme | http | https |
request.secure | false | true |
request.serverPort | 80 | 443 |
x-forwarded-by
header is null because only internal proxies as been traversed
by the request. x-forwarded-by
is null because all the proxies are trusted or
internal.
Sample with trusted proxies
XForwardedFilter configuration:
<filter>
<filter-name>XForwardedFilter</filter-name>
<filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class>
<init-param>
<param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value>
</init-param>
<init-param>
<param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value>
</init-param>
<init-param>
<param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value>
</init-param>
<init-param>
<param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XForwardedFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Request values:
property | Value Before XForwardedFilter | Value After XForwardedFilter |
---|---|---|
request.remoteAddr | 192.168.0.10 | 140.211.11.130 |
request.header['x-forwarded-for'] | 140.211.11.130, proxy1, proxy2 | null |
request.header['x-forwarded-by'] | null | proxy1, proxy2 |
proxy1
and proxy2
are both trusted proxies that come in
x-forwarded-for
header, they both are migrated in x-forwarded-by
header. x-forwarded-by
is null because all the proxies are trusted or internal.
Sample with internal and trusted proxies
XForwardedFilter configuration:
<filter>
<filter-name>XForwardedFilter</filter-name>
<filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class>
<init-param>
<param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value>
</init-param>
<init-param>
<param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value>
</init-param>
<init-param>
<param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value>
</init-param>
<init-param>
<param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XForwardedFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Request values:
property | Value Before XForwardedFilter | Value After XForwardedFilter |
---|---|---|
request.remoteAddr | 192.168.0.10 | 140.211.11.130 |
request.header['x-forwarded-for'] | 140.211.11.130, proxy1, proxy2, 192.168.0.10 | null |
request.header['x-forwarded-by'] | null | proxy1, proxy2 |
proxy1
and proxy2
are both trusted proxies that come in
x-forwarded-for
header, they both are migrated in x-forwarded-by
header. As 192.168.0.10
is an internal proxy, it does not appear in
x-forwarded-by
. x-forwarded-by
is null because all the proxies are
trusted or internal.
Sample with an untrusted proxy
XForwardedFilter configuration:
<filter>
<filter-name>XForwardedFilter</filter-name>
<filter-class>fr.xebia.servlet.filter.XForwardedFilter</filter-class>
<init-param>
<param-name>allowedInternalProxies</param-name><param-value>192\.168\.0\.10, 192\.168\.0\.11</param-value>
</init-param>
<init-param>
<param-name>remoteIPHeader</param-name><param-value>x-forwarded-for</param-value>
</init-param>
<init-param>
<param-name>remoteIPProxiesHeader</param-name><param-value>x-forwarded-by</param-value>
</init-param>
<init-param>
<param-name>trustedProxies</param-name><param-value>proxy1, proxy2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>XForwardedFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Request values:
property | Value Before XForwardedFilter | Value After XForwardedFilter |
---|---|---|
request.remoteAddr | 192.168.0.10 | untrusted-proxy |
request.header['x-forwarded-for'] | 140.211.11.130, untrusted-proxy, proxy1 | 140.211.11.130 |
request.header['x-forwarded-by'] | null | proxy1 |
x-forwarded-by
holds the trusted proxy proxy1
.
x-forwarded-by
holds 140.211.11.130
because
untrusted-proxy
is not trusted and thus, we can not trust that
untrusted-proxy
is the actual remote ip. request.remoteAddr
is
untrusted-proxy
that is an IP verified by proxy1
.
Modifier and Type | Class and Description |
---|---|
static class |
XForwardedRequestWrapperFactory.Config
Filter Config
|
Modifier and Type | Field and Description |
---|---|
protected static String |
HTTP_SERVER_PORT_PARAMETER |
protected static String |
HTTPS_SERVER_PORT_PARAMETER |
protected static String |
INTERNAL_PROXIES_PARAMETER |
protected static String |
PROTOCOL_HEADER_PARAMETER |
protected static String |
PROTOCOL_HEADER_SSL_VALUE_PARAMETER |
protected static String |
PROXIES_HEADER_PARAMETER |
protected static String |
REMOTE_IP_HEADER_PARAMETER |
protected static String |
TRUSTED_PROXIES_PARAMETER |
Constructor and Description |
---|
XForwardedRequestWrapperFactory()
Construct.
|
Modifier and Type | Method and Description |
---|---|
XForwardedRequestWrapperFactory.Config |
getConfig() |
void |
init(javax.servlet.FilterConfig filterConfig) |
boolean |
needsWrapper(javax.servlet.http.HttpServletRequest request) |
javax.servlet.http.HttpServletRequest |
newRequestWrapper(javax.servlet.http.HttpServletRequest request) |
void |
setConfig(XForwardedRequestWrapperFactory.Config config)
The Wicket application might want to provide its own config
|
commaDelimitedListToPatternArray, commaDelimitedListToStringArray, getWrapper, isEnabled, listToCommaDelimitedString, matchesOne, setEnabled
protected static final String HTTP_SERVER_PORT_PARAMETER
protected static final String HTTPS_SERVER_PORT_PARAMETER
protected static final String INTERNAL_PROXIES_PARAMETER
protected static final String PROTOCOL_HEADER_PARAMETER
protected static final String PROTOCOL_HEADER_SSL_VALUE_PARAMETER
protected static final String PROXIES_HEADER_PARAMETER
protected static final String REMOTE_IP_HEADER_PARAMETER
protected static final String TRUSTED_PROXIES_PARAMETER
public XForwardedRequestWrapperFactory()
public final XForwardedRequestWrapperFactory.Config getConfig()
public final void setConfig(XForwardedRequestWrapperFactory.Config config)
config
- public boolean needsWrapper(javax.servlet.http.HttpServletRequest request)
needsWrapper
in class AbstractRequestWrapperFactory
public javax.servlet.http.HttpServletRequest newRequestWrapper(javax.servlet.http.HttpServletRequest request)
newRequestWrapper
in class AbstractRequestWrapperFactory
request
- public void init(javax.servlet.FilterConfig filterConfig)
filterConfig
- Copyright © 2006–2022 Apache Software Foundation. All rights reserved.