From d700aa0522000635d3bed58b6b41708f7473fc5c Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sat, 11 May 2024 16:02:15 +0200 Subject: [PATCH] Rework secure_login_only configuration option to allow secure default and header checking --- inc/config.php | 9 +++++++-- inc/functions/net.php | 16 +++++++--------- inc/mod/auth.php | 4 ++-- inc/mod/pages.php | 3 ++- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/inc/config.php b/inc/config.php index 2fd2ba08..e7089061 100644 --- a/inc/config.php +++ b/inc/config.php @@ -194,8 +194,13 @@ // Whether or not you can access the mod cookie in JavaScript. Most users should not need to change this. $config['cookies']['httponly'] = true; - // Do not allow logins via unencrypted HTTP. If your website uses HTTPS, turn this on. - $config['cookies']['secure_login_only'] = false; + // Do not allow logins via unsecure connections. + // 0 = off. Allow logins on unencrypted HTTP connections. Should only be used in testing environments. + // 1 = on, trust HTTP headers. Allow logins on (at least reportedly partial) HTTPS connections. Use this only if you + // use a proxy, CDN or load balancer via an unencrypted connection. Be sure to filter 'HTTP_X_FORWARDED_PROTO' in + // the remote server, since an attacker could inject the header from the client. + // 2 = on, do not trust HTTP headers. Secure default, allow logins only on HTTPS connections. + $config['cookies']['secure_login_only'] = 2; // Used to salt secure tripcodes ("##trip") and poster IDs (if enabled). $config['secure_trip_salt'] = ')(*&^%$#@!98765432190zyxwvutsrqponmlkjihgfedcba'; diff --git a/inc/functions/net.php b/inc/functions/net.php index ebf578e7..e1541046 100644 --- a/inc/functions/net.php +++ b/inc/functions/net.php @@ -3,16 +3,14 @@ namespace Vichan\Functions\Net; /** + * @param bool $trust_headers. If true, trust the `HTTP_X_FORWARDED_PROTO` header to check if the connection is HTTPS. * @return bool Returns if the client-server connection is an encrypted one (HTTPS). */ -function is_connection_secure(): bool { - if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { - return true; - } - elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { - return true; - } - else { +function is_connection_secure(bool $trust_headers): bool { + if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { + return true; + } elseif ($trust_headers && isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { + return true; + } return false; - } } diff --git a/inc/mod/auth.php b/inc/mod/auth.php index 46da5cdb..ec9d6057 100644 --- a/inc/mod/auth.php +++ b/inc/mod/auth.php @@ -118,7 +118,7 @@ function setCookies(): void { error('setCookies() was called for a non-moderator!'); } - $is_https = Net\is_connection_secure(); + $is_https = Net\is_connection_secure($config['cookies']['secure_login_only'] === 1); $is_path_jailed = $config['cookies']['jail']; $name = calc_cookie_name($is_https, $is_path_jailed, $config['cookies']['mod']); @@ -235,7 +235,7 @@ function make_secure_link_token(string $uri): string { function check_login(bool $prompt = false): void { global $config, $mod; - $is_https = Net\is_connection_secure(); + $is_https = Net\is_connection_secure($config['cookies']['secure_login_only'] === 1); $is_path_jailed = $config['cookies']['jail']; $expected_cookie_name = calc_cookie_name($is_https, $is_path_jailed, $config['cookies']['mod']); diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 34f920fd..bfae5bbb 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -35,7 +35,8 @@ function mod_login($redirect = false) { $args = []; - if ($config['cookies']['secure_login_only'] && !Net\is_connection_secure()) { + $secure_login_mode = $config['cookies']['secure_login_only']; + if ($secure_login_mode !== 0 && !Net\is_connection_secure($secure_login_mode === 1)) { $args['error'] = $config['error']['insecure']; } elseif (isset($_POST['login'])) { // Check if inputs are set and not empty