juanpablo-santos commented on code in PR #517:
URL: https://github.com/apache/jspwiki/pull/517#discussion_r4045922575


##########
jspwiki-util/src/main/java/org/apache/wiki/util/HttpUtil.java:
##########
@@ -46,27 +50,107 @@ public final class HttpUtil {
     private static final int    ONE                   = 48;
     private static final int    NINE                  = 57;
     private static final int    DOT                   = 46;
+
+    /**
+     * Name of the system property holding the comma-separated list of reverse 
proxies (exact IPs or IPv4 CIDR
+     * ranges) whose {@code X-Forwarded-For} header may be trusted. Empty or 
unset means the header is never trusted.
+     */
+    public static final String PROP_TRUSTED_PROXIES = "jspwiki.trustedProxies";
+
+    /** Characters allowed in an IPv4 / IPv6 address. */
+    private static final Pattern IP_ADDRESS_CHARS = Pattern.compile( 
"[0-9A-Fa-f.:]{1,45}" );
+
+    /** Cached parse of {@value #PROP_TRUSTED_PROXIES}; {@code null} until 
first used. */
+    private static volatile Set<String> trustedProxies;
     
     /** Private constructor to prevent direct instantiation. */
     private HttpUtil() {
     }
     
     /**
-     * returns the remote address by looking into {@code x-forwarded-for} 
header or, if unavailable, 
-     * into {@link HttpServletRequest#getRemoteAddr()}.
-     * 
+     * Returns the remote address of the request. By default this is {@link 
HttpServletRequest#getRemoteAddr()}:
+     * the client-supplied {@code X-Forwarded-For} header is only consulted 
when the immediate peer is listed in
+     * the {@value #PROP_TRUSTED_PROXIES} system property. When it is, the 
forwarded entries are walked from the
+     * one appended by the nearest trusted proxy towards the client, and the 
first address that does not belong to
+     * a trusted proxy is returned, so a client cannot spoof its address by 
pre-populating the header. Values that
+     * do not look like an IP address fall back to {@link 
HttpServletRequest#getRemoteAddr()}.
+     *
      * @param req http request
      * @return remote address associated to the request.
      */
     public static String getRemoteAddress( final HttpServletRequest req ) {
-        String realIP = StringUtils.isNotEmpty ( req.getHeader( 
"X-Forwarded-For" ) ) ? req.getHeader( "X-Forwarded-For" ) :
-                                                                               
           req.getRemoteAddr();
-        // can be a comma-separated list of IPs
-        if (realIP.contains(","))
-                realIP = realIP.substring(realIP.indexOf(","));
-
-        return realIP;
-       
+        final String remoteAddr = req.getRemoteAddr();
+        if( !isTrustedProxy( remoteAddr ) ) {
+            return remoteAddr;
+        }
+
+        // there may be several X-Forwarded-For headers, each holding a 
comma-separated list of addresses
+        final StringBuilder forwarded = new StringBuilder();
+        final Enumeration<String> headers = req.getHeaders( "X-Forwarded-For" 
);
+        while( headers != null && headers.hasMoreElements() ) {
+            if( forwarded.length() > 0 ) {
+                forwarded.append( ',' );
+            }
+            forwarded.append( headers.nextElement() );
+        }
+        if( forwarded.length() == 0 ) {
+            return remoteAddr;
+        }
+
+        final String[] hops = forwarded.toString().split( "," );
+        for( int i = hops.length - 1; i >= 0; i-- ) {
+            final String hop = hops[ i ].trim();
+            if( !isTrustedProxy( hop ) ) {
+                return IP_ADDRESS_CHARS.matcher( hop ).matches() ? hop : 
remoteAddr;
+            }
+        }
+        return remoteAddr;
+    }
+
+    /**
+     * Returns whether the given address matches an entry of the {@value 
#PROP_TRUSTED_PROXIES} system property.
+     *
+     * @param addr address to check.
+     * @return {@code true} if the address is a trusted proxy, {@code false} 
otherwise.
+     */
+    static boolean isTrustedProxy( final String addr ) {

Review Comment:
   it'd be better if `PROP_TRUSTED_PROXIES` could also be configured through 
wiki properties or env vars.. check with comments at JSPWIKI-1294



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to