Add trusted_proxies config

This commit is contained in:
Joe Cooper
2026-05-10 01:19:01 -05:00
parent f78413549b
commit 241abfe719
5 changed files with 61 additions and 3 deletions

View File

@@ -1469,6 +1469,19 @@ if ($headerhost) {
$headerhost = undef if (!&check_ipaddress($headerhost) &&
!&check_ip6address($headerhost));
}
# If trusted_proxies is configured, header-supplied client IP and SSL
# client info are only honored when the direct TCP peer is in that list.
# Otherwise drop them so an attacker reaching miniserv directly cannot
# spoof X-Forwarded-For or X-SSL-Client-* to bypass auth.
if ($config{'trust_real_ip'} && $config{'trusted_proxies'} ne '' &&
!&ip_match($acptip, $localip,
split(/\s+/, $config{'trusted_proxies'}))) {
print DEBUG "handle_request: peer $acptip not in trusted_proxies; ".
"ignoring forwarding and SSL client headers\n";
$headerhost = undef;
delete $header{'x-ssl-client-dn'};
delete $header{'x-ssl-client-verify'};
}
if ($config{'trust_real_ip'}) {
$acpthost = $headerhost || $acpthost;
if (&check_ipaddress($headerhost) || &check_ip6address($headerhost)) {
@@ -1723,7 +1736,7 @@ if ($header{'user-agent'} =~ /webmin/i ||
my $trust_ssl = $config{'trust_real_ip'} && !$config{'no_trust_ssl'};
if ($use_ssl && $verified_client ||
$trust_ssl && $header{'x-ssl-client-dn'} &&
$header{'x-ssl-client-verify'} =~ /^success/i) {
$header{'x-ssl-client-verify'} =~ /^success$/i) {
if ($use_ssl && $verified_client) {
$peername = Net::SSLeay::X509_NAME_oneline(
Net::SSLeay::X509_get_subject_name(
@@ -1731,8 +1744,12 @@ if ($use_ssl && $verified_client ||
$ssl_con)));
$u = &find_user_by_cert($peername);
}
if ($trust_ssl && !$u && $header{'x-ssl-client-dn'}) {
# Use proxied client cert
if ($trust_ssl && !$u && $header{'x-ssl-client-dn'} &&
!($use_ssl && $verified_client)) {
# Use proxied client cert (only when this connection
# is not itself a verified mTLS client; otherwise the
# header could be set by a real-cert client that didn't
# match a user, to authenticate as someone else).
$u = &find_user_by_cert($header{'x-ssl-client-dn'});
}
if ($u) {

View File

@@ -30,6 +30,15 @@ if (!$@ && $in{'libwrap'}) {
}
}
@tprox = split(/\s+/, $in{'trusted_proxies'});
foreach $h (@tprox) {
$err = &valid_allow($h);
&error($err) if ($err);
}
if ($in{'trust'} == 2 && !@tprox) {
&error($text{'access_etproxies'});
}
&lock_file($ENV{'MINISERV_CONFIG'});
&get_miniserv_config(\%miniserv);
delete($miniserv{"allow"});
@@ -52,6 +61,7 @@ else {
$miniserv{'trust_real_ip'} = 0;
$miniserv{'no_trust_ssl'} = 1;
}
$miniserv{'trusted_proxies'} = join(' ', @tprox);
&put_miniserv_config(\%miniserv);
&unlock_file($ENV{'MINISERV_CONFIG'});
&show_restart_page();

View File

@@ -38,6 +38,10 @@ print &ui_table_row(&hlink($text{'access_trust_lvl'}, "access_trust_lvl"),
[ 1, $text{'access_trust_lvl1'} ],
[ 2, $text{'access_trust_lvl2'} ] ]));
@tprox = split(/\s+/, $miniserv{'trusted_proxies'});
print &ui_table_row(&hlink($text{'access_tproxies'}, "access_tproxies"),
&ui_textarea("trusted_proxies", join("\n", @tprox), 4, 30));
eval "use Authen::Libwrap qw(hosts_ctl STRING_UNKNOWN)";
if (!$@) {
print &ui_table_row($text{'access_libwrap'},

View File

@@ -0,0 +1,25 @@
<header>Trusted proxy addresses</header>
A list of IP addresses or networks (one per line, in the same format as the
allowed addresses field above) that are permitted to provide proxy headers
such as <tt>X-Forwarded-For</tt>, <tt>X-Real-IP</tt>, <tt>X-SSL-Client-DN</tt>
and <tt>X-SSL-Client-Verify</tt>.
<p>
When this list is set, headers received from any other peer are ignored,
preventing a client that can reach Webmin directly from spoofing its source
IP or impersonating a user via a fake SSL client certificate header.
<p>
This field is required when the trust level is set to trust both the remote
IP and SSL certificate provided by proxies. It is strongly recommended
whenever any proxy header trust is enabled.
<p>
Example:
<pre>
10.0.0.5
192.168.1.0/24
2001:DB8::/32
</pre>
<p></p>

View File

@@ -35,6 +35,8 @@ access_trust_lvl=Trust level for proxy headers
access_trust_lvl0=No, do not trust any headers from the proxy
access_trust_lvl1=Yes, trust the remote IP address provided by proxies
access_trust_lvl2=Yes, trust both the remote IP and SSL cert provided by proxies
access_tproxies=Trusted proxy addresses
access_etproxies=At least one trusted proxy address must be entered when trusting the remote IP and SSL cert from proxies
bind_title=Ports and Addresses
bind_desc2=This form can be used to change the port number that Webmin listens on, or have it listen on only a single IP address on your system. You can also configure it to accept connections on multiple ports, or to listen on several IP addresses. Note - your web browser may prompt you to log in again after changing the port or binding address.