Merge pull request #2514 from webmin/dev/option-enforce-ssl

Add the ability to re-enforce SSL connections and enable it by default
This commit is contained in:
Jamie Cameron
2025-07-07 08:53:24 +10:00
committed by GitHub
8 changed files with 54 additions and 93 deletions

View File

@@ -1375,91 +1375,38 @@ local $origreqline = &read_line();
$method = $page = $request_uri = undef;
print DEBUG "handle_request reqline=$reqline\n";
alarm(0);
if (!$reqline && (!$use_ssl || $checked_timeout > 1)) {
if (!$use_ssl && $config{'ssl'} && $config{'ssl_enforce'}) {
# This is an http request when https must be enforced
local $urlhost = $config{'musthost'} || $host;
$urlhost = "[".$urlhost."]" if (&check_ip6address($urlhost));
local $wantport = $port;
if ($wantport == 80 &&
&indexof(443, @listening_on_ports) >= 0) {
# Connection was to port 80, but since we are also
# accepting on port 443, redirect to that
$wantport = 443;
}
local $url = $wantport == 443
? "https://$urlhost/"
: "https://$urlhost:$wantport/";
&write_data("HTTP/1.0 302 Moved Temporarily\r\n");
&write_data("Date: $datestr\r\n");
&write_data("Server: @{[&server_info()]}\r\n");
&write_data("Location: $url\r\n");
&write_keep_alive(0);
&write_data("\r\n");
&log_error("Redirecting HTTP request to HTTPS for $acptip");
&log_request($loghost, $authuser, $reqline, 302, 0);
return 0;
}
elsif (!$reqline && $checked_timeout > 1) {
# An empty request .. just close the connection
print DEBUG "handle_request: rejecting empty request\n";
return 0;
}
elsif ($reqline !~ /^(\S+)\s+(.*)\s+HTTP\/1\..$/) {
print DEBUG "handle_request: invalid reqline=$reqline\n";
if ($use_ssl) {
# This could be an http request when it should be https
$use_ssl = 0;
local $urlhost = $config{'musthost'} || $host;
$urlhost = "[".$urlhost."]" if (&check_ip6address($urlhost));
local $wantport = $port;
if ($wantport == 80 &&
&indexof(443, @listening_on_ports) >= 0) {
# Connection was to port 80, but since we are also
# accepting on port 443, redirect to that
$wantport = 443;
}
local $url = $wantport == 443 ? "https://$urlhost/"
: "https://$urlhost:$wantport/";
local $jsurl = $config{'musthost'} ?
$url :
"https://'+location.host+'";
local $jsredir = $config{'musthost'} ?
"location.href='$url'" :
"location.protocol='https:'";
$reqline = "GET / HTTP/1.1"; # Fake it for the log
&http_error(200, "Document follows",
"This web server is running in SSL mode. ".
"Trying to redirect to <a href='$url'>$url</a> instead ...".
"<script>".
"if (location.protocol != 'https:') {".
" document.querySelector('a').href='".$jsurl."';document.querySelector('a').innerText='".$jsurl."';".
"".$jsredir."".
"}".
"</script>",
0, 1);
}
elsif (ord(substr($reqline, 0, 1)) == 128 && !$use_ssl) {
# This could be an https request when it should be http ..
# need to fake a HTTP response
eval <<'EOF';
use Net::SSLeay;
eval "Net::SSLeay::SSLeay_add_ssl_algorithms()";
eval "Net::SSLeay::load_error_strings()";
$ssl_ctx = Net::SSLeay::CTX_new();
Net::SSLeay::CTX_use_RSAPrivateKey_file(
$ssl_ctx, $config{'keyfile'},
&Net::SSLeay::FILETYPE_PEM);
Net::SSLeay::CTX_use_certificate_file(
$ssl_ctx,
$config{'certfile'} || $config{'keyfile'},
&Net::SSLeay::FILETYPE_PEM);
$ssl_con = Net::SSLeay::new($ssl_ctx);
pipe(SSLr, SSLw);
if (!fork()) {
close(SSLr);
select(SSLw); $| = 1; select(STDOUT);
print SSLw $origreqline;
local $buf;
while(sysread(SOCK, $buf, 1) > 0) {
print SSLw $buf;
}
close(SOCK);
exit;
}
close(SSLw);
Net::SSLeay::set_wfd($ssl_con, fileno(SOCK));
Net::SSLeay::set_rfd($ssl_con, fileno(SSLr));
Net::SSLeay::accept($ssl_con) || die "accept() failed";
$use_ssl = 1;
local $url = $config{'musthost'} ?
"https://$config{'musthost'}:$port/" :
"https://$host:$port/";
$reqline = "GET / HTTP/1.1"; # Fake it for the log
&http_error(200, "Bad Request", "This web server is not running in SSL mode. Try the URL <a href='$url'>$url</a> instead.", 0, 1);
EOF
if ($@) {
&http_error(400, "Bad Request");
}
}
else {
&http_error(400, "Bad Request");
}
&http_error(400, "Bad Request");
return 0;
}
$method = $1;
$request_uri = $page = $2;

View File

@@ -826,6 +826,9 @@ if [ "$upgrading" != 1 ]; then
# Enable HSTS by default
echo "ssl_hsts=1" >> $config_dir/miniserv.conf
# Enable force redirect to SSL by default
echo "ssl_enforce=1" >> $config_dir/miniserv.conf
# Disallow unknown referers by default
echo "referers_none=1" >>$config_dir/config
else
@@ -835,6 +838,12 @@ else
echo "ssl_hsts=1" >> $config_dir/miniserv.conf
fi
# Enable force redirect to SSL if not set
grep ssl_enforce= $config_dir/miniserv.conf >/dev/null
if [ "$?" != "0" ]; then
echo "ssl_enforce=1" >> $config_dir/miniserv.conf
fi
# Disallow unknown referers if not set
grep referers_none= $config_dir/config >/dev/null
if [ "$?" != "0" ]; then

View File

@@ -10,7 +10,8 @@ require './usermin-lib.pl';
&get_usermin_miniserv_config(\%miniserv);
$sslcurr = $miniserv{'ssl'};
$miniserv{'ssl'} = $in{'ssl'};
$miniserv{'ssl_hsts'} = ($in{'ssl'} && $in{'ssl_hsts'}) ? 1 : 0;
$miniserv{'ssl_enforce'} = int($in{'ssl_enforce'});
$miniserv{'ssl_hsts'} = $miniserv{'ssl_enforce'} == 2 ? 1 : 0;
&webmin::validate_key_cert($in{'key'}, $in{'cert_def'} ? undef : $in{'cert'});
$miniserv{'keyfile'} = $in{'key'};
$miniserv{'certfile'} = $in{'cert_def'} ? undef : $in{'cert'};

View File

@@ -15,7 +15,6 @@ print &ui_tabs_start(\@tabs, "mode", $in{'mode'} || $tabs[0]->[0], 1);
# Basic SSL settings
print &ui_tabs_start_tab("mode", "ssl");
print $text{'ssl_desc1'},"<p>\n";
print $text{'ssl_desc2'},"<p>\n";
print &ui_form_start("change_ssl.cgi", "post");
print &ui_table_start($text{'ssl_header'}, undef, 2);
@@ -23,8 +22,11 @@ print &ui_table_start($text{'ssl_header'}, undef, 2);
print &ui_table_row($text{'ssl_on'},
&ui_yesno_radio("ssl", $miniserv{'ssl'}));
print ui_table_row($text{'ssl_hsts'},
ui_yesno_radio("ssl_hsts", $miniserv{'ssl_hsts'}));
print ui_table_row($text{'ssl_enforce'},
ui_radio("ssl_enforce", $miniserv{'ssl_enforce'} // 1,
[ [ 2, $text{'ssl_hsts'} ],
[ 1, $text{'yes'} ],
[ 0, $text{'no'} ] ]));
print &ui_table_row($text{'ssl_key'},
&ui_textbox("key", $miniserv{'keyfile'}, 40)." ".

View File

@@ -130,8 +130,7 @@ acl_title=Available Modules
acl_desc=Use this page to select which installed Usermin modules are visible to users.
ssl_title=SSL Encryption
ssl_desc1=The host on which Usermin is running appears to have the SSLeay Perl module installed. Using this, Usermin supports SSL encrypted communication between your browser and the server. If users are accessing your Usermin server over the Internet, then you should definitely consider using SSL to prevent an attacker capturing their passwords.
ssl_desc2=Warning - only turn on SSL support if you have a browser that supports SSL, and there is no firewall blocking <tt>https</tt> requests between your browser and the Usermin host.
ssl_desc1=Usermin can use SSL to encrypt the connection between your browser and the server. If you connect to Usermin over the internet, always use SSL to protect your password and prevent man-in-the-middle attacks.
ssl_newkey=This form can be used to create a new SSL key for your Usermin server.
ssl_hole=Because you are currently using the default Usermin SSL key that everyone has access to, you should generate a new key immediately. Otherwise your SSL connection is not secure!
ssl_savekey=This form allows you to upload an existing PEM format SSL private key and certificate for your Usermin server to use.

View File

@@ -10,7 +10,8 @@ require './webmin-lib.pl';
&get_miniserv_config(\%miniserv);
$sslcurr = $miniserv{'ssl'};
$miniserv{'ssl'} = $in{'ssl'};
$miniserv{'ssl_hsts'} = ($in{'ssl'} && $in{'ssl_hsts'}) ? 1 : 0;
$miniserv{'ssl_enforce'} = int($in{'ssl_enforce'});
$miniserv{'ssl_hsts'} = $miniserv{'ssl_enforce'} == 2 ? 1 : 0;
&validate_key_cert($in{'key'}, $in{'cert_def'} ? undef : $in{'cert'});
$miniserv{'keyfile'} = $in{'key'};
$miniserv{'certfile'} = $in{'cert_def'} ? undef : $in{'cert'};

View File

@@ -48,7 +48,6 @@ print ui_tabs_start(\@tabs, "mode", $in{'mode'} || $tabs[0]->[0], 1);
# Basic SSL settings
print ui_tabs_start_tab("mode", "ssl");
print $text{'ssl_desc1'},"<p>\n";
print $text{'ssl_desc2'},"<p>\n";
print ui_form_start("change_ssl.cgi", "post");
print ui_table_start($text{'ssl_header'}, undef, 2);
@@ -56,8 +55,11 @@ print ui_table_start($text{'ssl_header'}, undef, 2);
print ui_table_row($text{'ssl_on'},
ui_yesno_radio("ssl", $miniserv{'ssl'}));
print ui_table_row($text{'ssl_hsts'},
ui_yesno_radio("ssl_hsts", $miniserv{'ssl_hsts'}));
print ui_table_row($text{'ssl_enforce'},
ui_radio("ssl_enforce", $miniserv{'ssl_enforce'} // 1,
[ [ 2, $text{'ssl_hsts'} ],
[ 1, $text{'yes'} ],
[ 0, $text{'no'} ] ]));
print ui_table_row($text{'ssl_key'},
ui_textbox("key", $miniserv{'keyfile'}, 40)." ".

View File

@@ -339,8 +339,7 @@ ssl_title=SSL Encryption
ssl_essl=The Net::SSLeay perl module does not appear to be installed on your system. To install the OpenSSL library and Net::SSLeay, follow <a href='$1'>these instructions</a> from the Webmin website.
ssl_cpan=Alternately, you can have Webmin <a href='$1'>download and install</a> the required Net::SSLeay Perl module for you.
ssl_emessage=The error message from Perl was : $1
ssl_desc1=The host on which Webmin is running appears to have the SSLeay Perl module installed. Using this, Webmin supports SSL encrypted communication between your browser and the server. If you are accessing your Webmin server over the Internet, then you should definitely consider using SSL to prevent an attacker capturing your Webmin password.
ssl_desc2=Warning - only turn on SSL support if you have a browser that supports SSL, and there is no firewall blocking <b>https</b> requests between your browser and the Webmin host.
ssl_desc1=Webmin can use SSL to encrypt the connection between your browser and the server. If you connect to Webmin over the internet, always use SSL to protect your password and prevent man-in-the-middle attacks.
ssl_header=SSL support
ssl_on=Enable SSL?
ssl_key=Private key file
@@ -351,7 +350,8 @@ ssl_deny=SSL protocol versions to reject
ssl_compression=Allow compressed SSL connections?
ssl_honorcipherorder=Force use of server-defined cipher order?
ssl_extracas=Additional certificate files<br>for chained certificates
ssl_hsts=Enforce SSL with HSTS header
ssl_enforce=Enforce SSL
ssl_hsts=Yes, with HSTS header
ssl_redirect=Redirecting after protocol change ..
ssl_extracasdef=Same as global SSL settings
ssl_extracasnone=None for this IP address