From 6b7567253458da08cd36960513f13c5600760c81 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 6 Jul 2025 20:02:34 +0300 Subject: [PATCH 1/4] Add ability to enforce SSL by default --- miniserv.pl | 109 ++++++++++++++-------------------------------------- setup.sh | 9 +++++ 2 files changed, 37 insertions(+), 81 deletions(-) diff --git a/miniserv.pl b/miniserv.pl index f94f94f41..28c22c9f8 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -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"; + print STDERR "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 $url instead ...". - "", - 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 $url 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; diff --git a/setup.sh b/setup.sh index 5a49a10c1..177f800ad 100755 --- a/setup.sh +++ b/setup.sh @@ -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 From 11de78ce5144dde32895b88996e5c56ee74960df Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 6 Jul 2025 20:24:06 +0300 Subject: [PATCH 2/4] Add ability to configure SSL enforcement options in UI --- usermin/change_ssl.cgi | 3 ++- usermin/edit_ssl.cgi | 7 +++++-- webmin/change_ssl.cgi | 3 ++- webmin/edit_ssl.cgi | 7 +++++-- webmin/lang/en | 3 ++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/usermin/change_ssl.cgi b/usermin/change_ssl.cgi index be38a16a1..747ce302c 100755 --- a/usermin/change_ssl.cgi +++ b/usermin/change_ssl.cgi @@ -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'}; diff --git a/usermin/edit_ssl.cgi b/usermin/edit_ssl.cgi index 61d78906d..4806011c7 100755 --- a/usermin/edit_ssl.cgi +++ b/usermin/edit_ssl.cgi @@ -23,8 +23,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)." ". diff --git a/webmin/change_ssl.cgi b/webmin/change_ssl.cgi index 1d8d7f4a3..b3509fb98 100755 --- a/webmin/change_ssl.cgi +++ b/webmin/change_ssl.cgi @@ -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'}; diff --git a/webmin/edit_ssl.cgi b/webmin/edit_ssl.cgi index 35aea0182..339527d50 100755 --- a/webmin/edit_ssl.cgi +++ b/webmin/edit_ssl.cgi @@ -56,8 +56,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)." ". diff --git a/webmin/lang/en b/webmin/lang/en index 2b3ac36ea..7cff4f820 100644 --- a/webmin/lang/en +++ b/webmin/lang/en @@ -351,7 +351,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
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 From 24cd121642e932e2429c36fa1b1c01a51c41eeea Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 6 Jul 2025 20:41:24 +0300 Subject: [PATCH 3/4] Update outdated SSL explanations --- usermin/edit_ssl.cgi | 1 - usermin/lang/en | 3 +-- webmin/edit_ssl.cgi | 1 - webmin/lang/en | 3 +-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/usermin/edit_ssl.cgi b/usermin/edit_ssl.cgi index 4806011c7..0cb0d5120 100755 --- a/usermin/edit_ssl.cgi +++ b/usermin/edit_ssl.cgi @@ -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'},"

\n"; -print $text{'ssl_desc2'},"

\n"; print &ui_form_start("change_ssl.cgi", "post"); print &ui_table_start($text{'ssl_header'}, undef, 2); diff --git a/usermin/lang/en b/usermin/lang/en index 18b5711c0..e725a3412 100644 --- a/usermin/lang/en +++ b/usermin/lang/en @@ -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 https 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. diff --git a/webmin/edit_ssl.cgi b/webmin/edit_ssl.cgi index 339527d50..e08fd353f 100755 --- a/webmin/edit_ssl.cgi +++ b/webmin/edit_ssl.cgi @@ -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'},"

\n"; -print $text{'ssl_desc2'},"

\n"; print ui_form_start("change_ssl.cgi", "post"); print ui_table_start($text{'ssl_header'}, undef, 2); diff --git a/webmin/lang/en b/webmin/lang/en index 7cff4f820..c5cf373c1 100644 --- a/webmin/lang/en +++ b/webmin/lang/en @@ -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 these instructions from the Webmin website. ssl_cpan=Alternately, you can have Webmin download and install 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 https 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 From f353ae31d8dfebd77d17dc4f631a90ebea2baff1 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 6 Jul 2025 20:44:35 +0300 Subject: [PATCH 4/4] Fix typos --- miniserv.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miniserv.pl b/miniserv.pl index 28c22c9f8..6e96b2667 100755 --- a/miniserv.pl +++ b/miniserv.pl @@ -1395,13 +1395,13 @@ if (!$use_ssl && $config{'ssl'} && $config{'ssl_enforce'}) { &write_data("Location: $url\r\n"); &write_keep_alive(0); &write_data("\r\n"); - log_error("Redirecting HTTP request to HTTPS for $acptip"); + &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 STDERR "handle_request: rejecting empty request\n"; + print DEBUG "handle_request: rejecting empty request\n"; return 0; } elsif ($reqline !~ /^(\S+)\s+(.*)\s+HTTP\/1\..$/) {