Another feature of this valve 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 valve proceeds as follows:
If the incoming request.getRemoteAddr()
matches the valve'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:
RemoteIpValve property | Description | Equivalent mod_remoteip directive | Format | Default Value |
---|---|---|---|---|
remoteIpHeader | Name of the Http Header read by this valve that holds the list of traversed IP addresses starting from the requesting client | RemoteIPHeader | Compliant http header name | x-forwarded-for |
internalProxies | 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 {@link java.util.regex.Pattern} library) | 10\.\d{1,3}\.\d{1,3}\.\d{1,3}, 192\.168\.\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, 169.254/16 and 127/8 are allowed ; 172.16/12 has not been enabled by default because it is complex to describe with regular expressions |
proxiesHeader | Name of the http header created by this valve 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 {@link java.util.regex.Pattern} library) | |
protocolHeader | Name of the http header read by this valve 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 {@link ServletRequest#getServerPort()} when the protocolHeader indicates http protocol | N/A | integer | 80 |
httpsServerPort | Value returned by {@link ServletRequest#getServerPort()} when the protocolHeader indicates https protocol | N/A | integer | 443 |
This Valve may be attached to any Container, depending on the granularity of the filtering you wish to perform.
Regular expression vs. IP address blocks: mod_remoteip
allows to use address blocks (e.g. 192.168/16
) to configure RemoteIPInternalProxy
and RemoteIPTrustedProxy
; as Tomcat doesn't have a library similar to apr_ipsubnet_test, RemoteIpValve
uses regular expression to configure internalProxies
and trustedProxies
in the same fashion as {@link RequestFilterValve} does.
Sample with internal proxies
RemoteIpValve configuration:
<Valve className="org.apache.catalina.valves.RemoteIpValve" internalProxies="192\.168\.0\.10, 192\.168\.0\.11" remoteIpHeader="x-forwarded-for" remoteIpProxiesHeader="x-forwarded-by" protocolHeader="x-forwarded-proto" />
Request values:
property | Value Before RemoteIpValve | Value After RemoteIpValve |
---|---|---|
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
RemoteIpValve configuration:
<Valve className="org.apache.catalina.valves.RemoteIpValve" internalProxies="192\.168\.0\.10, 192\.168\.0\.11" remoteIpHeader="x-forwarded-for" remoteIpProxiesHeader="x-forwarded-by" trustedProxies="proxy1, proxy2" />
Request values:
property | Value Before RemoteIpValve | Value After RemoteIpValve |
---|---|---|
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
RemoteIpValve configuration:
<Valve className="org.apache.catalina.valves.RemoteIpValve" internalProxies="192\.168\.0\.10, 192\.168\.0\.11" remoteIpHeader="x-forwarded-for" remoteIpProxiesHeader="x-forwarded-by" trustedProxies="proxy1, proxy2" />
Request values:
property | Value Before RemoteIpValve | Value After RemoteIpValve |
---|---|---|
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
RemoteIpValve configuration:
<Valve className="org.apache.catalina.valves.RemoteIpValve" internalProxies="192\.168\.0\.10, 192\.168\.0\.11" remoteIpHeader="x-forwarded-for" remoteIpProxiesHeader="x-forwarded-by" trustedProxies="proxy1, proxy2" />
Request values:
property | Value Before RemoteIpValve | Value After RemoteIpValve |
---|---|---|
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
.
|
|
|
|
|
|