mirror of
https://github.com/webmin/webmin.git
synced 2026-06-24 21:10:29 +01:00
Fix to restrict Basic auth for websocket routes
ⓘ Require websocket routes to opt in with allow_basic_ws before Basic auth is accepted in session mode. Mark linked ws-link routes and no-cookie backend-session routes as allowed, while leaving normal session-backed routes unmarked.
This commit is contained in:
15
miniserv.pl
15
miniserv.pl
@@ -1512,6 +1512,7 @@ alarm(0);
|
||||
my $websocket_upgrade_request = lc($header{'connection'}) =~ /upgrade/ &&
|
||||
lc($header{'upgrade'}) eq 'websocket';
|
||||
my $websocket_configured_request;
|
||||
my $websocket_basic_auth_ok;
|
||||
if ($websocket_upgrade_request) {
|
||||
# Check the configured websocket paths before auth, so Basic auth can
|
||||
# remain disabled for normal session-mode requests.
|
||||
@@ -1519,6 +1520,12 @@ if ($websocket_upgrade_request) {
|
||||
my $ws_simple = &simplify_path($page, $wsbogus);
|
||||
$websocket_configured_request = !$wsbogus &&
|
||||
&find_websocket_config($ws_simple);
|
||||
if ($websocket_configured_request) {
|
||||
# Session-mode Basic auth stays disabled unless the websocket
|
||||
# route explicitly allows a no-cookie Basic-auth hop.
|
||||
$websocket_basic_auth_ok =
|
||||
$websocket_configured_request->{'allow_basic_ws'};
|
||||
}
|
||||
}
|
||||
|
||||
# If a remote IP is given in a header (such as via a proxy), only use it
|
||||
@@ -1840,11 +1847,11 @@ if (!$validated && !$deny_authentication) {
|
||||
}
|
||||
}
|
||||
|
||||
# Keep Basic auth disabled in session mode except for configured websocket
|
||||
# proxy paths. Linked-server websocket hops need it, and token/user checks
|
||||
# still run before the backend connection is opened.
|
||||
# Keep Basic auth disabled in session mode except for websocket routes that
|
||||
# explicitly allow no-cookie Basic-auth hops. Token/user checks still run
|
||||
# before the backend connection is opened.
|
||||
if (!$validated && !$deny_authentication &&
|
||||
(!$config{'session'} || $websocket_configured_request) &&
|
||||
(!$config{'session'} || $websocket_basic_auth_ok) &&
|
||||
$header{authorization} =~ /^basic\s+(\S+)$/i) {
|
||||
# authorization given..
|
||||
($authuser, $authpass) = split(/:/, &b64decode($1), 2);
|
||||
|
||||
@@ -312,7 +312,7 @@ my %miniserv;
|
||||
$miniserv{"websockets_$wspath"} =
|
||||
"host=$backend_host port=$port ssl=$ssl wspath=$remote_path ".
|
||||
"hostheader=$hostheader origin=$origin auth=basic:$auth ".
|
||||
"checkssl=$checkssl nokey=1 user=$main::remote_user ".
|
||||
"checkssl=$checkssl nokey=1 allow_basic_ws=1 user=$main::remote_user ".
|
||||
"token=$token time=$now";
|
||||
&put_miniserv_config(\%miniserv);
|
||||
&unlock_file(&get_miniserv_config_file());
|
||||
|
||||
@@ -1311,7 +1311,7 @@ EOF
|
||||
subtest 'parse_websockets_config' => sub {
|
||||
no warnings 'once';
|
||||
local %miniserv::config = (
|
||||
'websockets_/chat' => 'host=back.example.com port=9000 proto=ws ssl=1 checkssl=1 backend_session=abc123',
|
||||
'websockets_/chat' => 'host=back.example.com port=9000 proto=ws ssl=1 checkssl=1 backend_session=abc123 allow_basic_ws=1',
|
||||
'unrelated_key' => 'ignored',
|
||||
);
|
||||
local @miniserv::websocket_paths = ();
|
||||
@@ -1326,6 +1326,7 @@ subtest 'parse_websockets_config' => sub {
|
||||
is($ws->{ssl}, '1', 'ssl kv parsed');
|
||||
is($ws->{checkssl}, '1', 'SSL check kv parsed');
|
||||
is($ws->{backend_session}, 'abc123', 'backend session kv parsed');
|
||||
is($ws->{allow_basic_ws}, '1', 'Basic auth websocket flag parsed');
|
||||
};
|
||||
|
||||
# find_websocket_config
|
||||
|
||||
@@ -14331,8 +14331,10 @@ my $opt_backend = "";
|
||||
# cookie. Store the one-time backend session key that the child server expects.
|
||||
$opt_backend = " backend_session=$backend_session"
|
||||
if (defined($backend_session) && $backend_session =~ /^\S+$/);
|
||||
my $opt_basic = "";
|
||||
$opt_basic = " allow_basic_ws=1" if ($opt_backend);
|
||||
$miniserv{"websockets_$wspath"} = "host=127.0.0.1 port=$port wspath=/ ".
|
||||
"user=$remote_user$opt_buser$opt_backend token=$token time=$now";
|
||||
"user=$remote_user$opt_buser$opt_backend$opt_basic token=$token time=$now";
|
||||
&put_miniserv_config(\%miniserv);
|
||||
&unlock_file(&get_miniserv_config_file());
|
||||
&reload_miniserv();
|
||||
|
||||
Reference in New Issue
Block a user