From a6cc22d845b1395c3ac53d288604d771a07d7a9a Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Wed, 30 Apr 2025 11:16:09 -0400 Subject: [PATCH] Bug 39789: Add ability to specify an alternative header to X-Forwarded-For for finding the real ip address Some services ( such as CloudFlare ) use alternative heads to X-Forwarded-For. Koha should be able to use a custom header instead of X-Forwarded-For if needed. This patch updates the feature to allow both the custom header and X-Forwarded-For to work harmoniously For example, CloudFlare has it's own custom header. This patch allows a site to be configured for Cloudflare's proxy before the proxy is enabled. Test Plan: 1) prove t/Koha/Middleware/RealIP.t Signed-off-by: Lin Wei Li --- C4/Context.pm | 7 ++++++- Koha/Middleware/RealIP.pm | 20 ++++++++++++-------- debian/templates/koha-conf-site.xml.in | 2 ++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/C4/Context.pm b/C4/Context.pm index 78602055164..752101ab23f 100644 --- a/C4/Context.pm +++ b/C4/Context.pm @@ -880,7 +880,12 @@ variable to be set correctly. sub set_remote_address { if ( C4::Context->config('koha_trusted_proxies') ) { require CGI; - my $header = CGI->http('HTTP_X_FORWARDED_FOR'); + + # If no reverse_proxy_ip_header, just use HTTP_X_FORWARDED_FOR as the header to check, simplifies logic and is a bit faster that way + my $reverse_proxy_ip_header = C4::Context->config('reverse_proxy_ip_header') || 'HTTP_X_FORWARDED_FOR'; + + # Check the cgi for the custom header, if the custom header is not set, fall back to HTTP_X_FORWARDED_FOR + my $header = CGI->http($reverse_proxy_ip_header) || CGI->http('HTTP_X_FORWARDED_FOR'); if ($header) { require Koha::Middleware::RealIP; diff --git a/Koha/Middleware/RealIP.pm b/Koha/Middleware/RealIP.pm index 352f484ea26..c33a3de76ff 100644 --- a/Koha/Middleware/RealIP.pm +++ b/Koha/Middleware/RealIP.pm @@ -51,14 +51,15 @@ sub call { my $self = shift; my $env = shift; - if ( $env->{HTTP_X_FORWARDED_FOR} ) { - my @trusted_proxy = $self->trusted_proxy ? @{ $self->trusted_proxy } : undef; - - if (@trusted_proxy) { - my $addr = get_real_ip( $env->{REMOTE_ADDR}, $env->{HTTP_X_FORWARDED_FOR}, \@trusted_proxy ); - $ENV{REMOTE_ADDR} = $addr; - $env->{REMOTE_ADDR} = $addr; - } + # If no reverse_proxy_ip_header, just use HTTP_X_FORWARDED_FOR as the header to check, simplifies logic and is a bit faster that way + my $reverse_proxy_ip_header = C4::Context->config('reverse_proxy_ip_header') || 'HTTP_X_FORWARDED_FOR'; + + # Check the env for the custom header, if the custom header is not set, fall back to HTTP_X_FORWARDED_FOR + my $header = $env->{$reverse_proxy_ip_header} || $env->{'HTTP_X_FORWARDED_FOR'}; + if ($header) { + my $addr = get_real_ip( $env->{REMOTE_ADDR}, $header ); + $ENV{REMOTE_ADDR} = $addr; + $env->{REMOTE_ADDR} = $addr; } return $self->app->($env); @@ -76,6 +77,9 @@ determines the correct external ip address, and returns it. sub get_real_ip { my ( $remote_addr, $header ) = @_; + my $require_trusted = C4::Context->config('require_trusted_proxy_for_headers') // 1; + return $remote_addr unless $require_trusted; + my @forwarded_for = $header =~ /([^,\s]+)/g; return $remote_addr unless @forwarded_for; diff --git a/debian/templates/koha-conf-site.xml.in b/debian/templates/koha-conf-site.xml.in index 0e07af36d8f..3d9525fc424 100644 --- a/debian/templates/koha-conf-site.xml.in +++ b/debian/templates/koha-conf-site.xml.in @@ -343,6 +343,8 @@ __END_SRU_PUBLICSERVER__ -- 2.50.1 (Apple Git-155)