Class XForwardedRequestWrapperFactory
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 :
- Loop on the comma delimited list of IPs and hostnames passed by the preceding load balancer
or proxy in the given request's Http header named
$remoteIPHeader
(default valuex-forwarded-for
). Values are processed in right-to-left order. - For each ip/host of the list:
- if it matches the internal proxies list, the ip/host is swallowed
- if it matches the trusted proxies list, the ip/host is added to the created proxies header
- otherwise, the ip/host is declared to be the remote ip and looping is stopped.
- If the request http header named
$protocolHeader
(e.g.x-forwarded-for
) equals to the value ofprotocolHeaderHttpsValue
configuration parameter (defaulthttps
) thenrequest.isSecure = true
,request.scheme = https
andrequest.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
.
- Author:
- Cyrille Le Clerc, Juergen Donnerstag
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic class
Filter Config -
Field Summary
-
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptionvoid
init
(jakarta.servlet.FilterConfig filterConfig) boolean
needsWrapper
(jakarta.servlet.http.HttpServletRequest request) jakarta.servlet.http.HttpServletRequest
newRequestWrapper
(jakarta.servlet.http.HttpServletRequest request) final void
The Wicket application might want to provide its own configMethods inherited from class org.apache.wicket.protocol.http.servlet.AbstractRequestWrapperFactory
commaDelimitedListToPatternArray, commaDelimitedListToStringArray, getWrapper, isEnabled, listToCommaDelimitedString, matchesOne, setEnabled
-
Field Details
-
HTTP_SERVER_PORT_PARAMETER
- See Also:
-
HTTPS_SERVER_PORT_PARAMETER
- See Also:
-
INTERNAL_PROXIES_PARAMETER
- See Also:
-
PROTOCOL_HEADER_PARAMETER
- See Also:
-
PROTOCOL_HEADER_SSL_VALUE_PARAMETER
- See Also:
-
PROXIES_HEADER_PARAMETER
- See Also:
-
REMOTE_IP_HEADER_PARAMETER
- See Also:
-
TRUSTED_PROXIES_PARAMETER
- See Also:
-
-
Constructor Details
-
XForwardedRequestWrapperFactory
public XForwardedRequestWrapperFactory()Construct.
-
-
Method Details
-
getConfig
- Returns:
- XForwarded filter specific config
-
setConfig
The Wicket application might want to provide its own config- Parameters:
config
-
-
needsWrapper
- Specified by:
needsWrapper
in classAbstractRequestWrapperFactory
- Returns:
- True, if a wrapper is needed
-
newRequestWrapper
public jakarta.servlet.http.HttpServletRequest newRequestWrapper(jakarta.servlet.http.HttpServletRequest request) - Specified by:
newRequestWrapper
in classAbstractRequestWrapperFactory
- Parameters:
request
-- Returns:
- Either the original request or the wrapper
-
init
- Parameters:
filterConfig
-
-