Skip to content

Commit 33cb4e0

Browse files
committed
Make is_ssl and baseurl use proper proxy checks
This should not only address dokuwiki#4455 but also ensures that the related headers are only used when they come from a trusted reverse proxy chain.
1 parent 6a9b330 commit 33cb4e0

File tree

5 files changed

+61
-49
lines changed

5 files changed

+61
-49
lines changed

inc/Ip.php

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
/**
4-
* DokuWiki IP address functions.
4+
* DokuWiki IP address and reverse proxy functions.
55
*
66
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
77
* @author Zebra North <[email protected]>
@@ -280,4 +280,51 @@ public static function clientIps(): array
280280

281281
return $ips;
282282
}
283+
284+
/**
285+
* Get the host name of the server.
286+
*
287+
* The host name is sourced from, in order of preference:
288+
*
289+
* - The X-Forwarded-Host header if it exists and the proxies are trusted.
290+
* - The HTTP_HOST header.
291+
* - The SERVER_NAME header.
292+
* - The system's host name.
293+
*
294+
* @return string Returns the host name of the server.
295+
*/
296+
public static function hostName(): string
297+
{
298+
/* @var Input $INPUT */
299+
global $INPUT;
300+
301+
if ($INPUT->server->str('HTTP_X_FORWARDED_HOST') && self::forwardedFor() !== []) {
302+
return $INPUT->server->str('HTTP_X_FORWARDED_HOST');
303+
} elseif ($INPUT->server->str('HTTP_HOST')) {
304+
return $INPUT->server->str('HTTP_HOST');
305+
} elseif ($INPUT->server->str('SERVER_NAME')) {
306+
return $INPUT->server->str('SERVER_NAME');
307+
} else {
308+
return php_uname('n');
309+
}
310+
}
311+
312+
/**
313+
* Is the connection using the HTTPS protocol?
314+
*
315+
* Will use the X-Forwarded-Proto header if it exists and the proxies are trusted, otherwise
316+
* the HTTPS environment is used.
317+
*
318+
* @return bool
319+
*/
320+
public static function isSsl(): bool
321+
{
322+
/* @var Input $INPUT */
323+
global $INPUT;
324+
325+
if ($INPUT->server->has('HTTP_X_FORWARDED_PROTO') && self::forwardedFor() !== []) {
326+
return $INPUT->server->str('HTTP_X_FORWARDED_PROTO') === 'https';
327+
}
328+
return preg_match('/^(|off|false|disabled)$/i', $INPUT->server->str('HTTPS', 'off'));
329+
}
283330
}

inc/auth.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ function auth_logoff($keepbc = false)
535535
setcookie(DOKU_COOKIE, '', [
536536
'expires' => time() - 600000,
537537
'path' => $cookieDir,
538-
'secure' => ($conf['securecookie'] && is_ssl()),
538+
'secure' => ($conf['securecookie'] && \dokuwiki\Ip::isSsl()),
539539
'httponly' => true,
540540
'samesite' => $conf['samesitecookie'] ?: null, // null means browser default
541541
]);
@@ -1401,7 +1401,7 @@ function auth_setCookie($user, $pass, $sticky)
14011401
setcookie(DOKU_COOKIE, $cookie, [
14021402
'expires' => $time,
14031403
'path' => $cookieDir,
1404-
'secure' => ($conf['securecookie'] && is_ssl()),
1404+
'secure' => ($conf['securecookie'] && \dokuwiki\Ip::isSsl()),
14051405
'httponly' => true,
14061406
'samesite' => $conf['samesitecookie'] ?: null, // null means browser default
14071407
]);

inc/common.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,7 @@ function set_doku_pref($pref, $val)
19571957
setcookie('DOKU_PREFS', $cookieVal, [
19581958
'expires' => time() + 365 * 24 * 3600,
19591959
'path' => $cookieDir,
1960-
'secure' => ($conf['securecookie'] && is_ssl()),
1960+
'secure' => ($conf['securecookie'] && Ip::isSsl()),
19611961
'samesite' => 'Lax'
19621962
]);
19631963
}

inc/init.php

Lines changed: 9 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ function init_session()
263263
'lifetime' => DOKU_SESSION_LIFETIME,
264264
'path' => DOKU_SESSION_PATH,
265265
'domain' => DOKU_SESSION_DOMAIN,
266-
'secure' => ($conf['securecookie'] && is_ssl()),
266+
'secure' => ($conf['securecookie'] && \dokuwiki\Ip::isSsl()),
267267
'httponly' => true,
268268
'samesite' => 'Lax',
269269
]);
@@ -497,28 +497,12 @@ function getBaseURL($abs = null)
497497
if (!empty($conf['baseurl'])) return rtrim($conf['baseurl'], '/') . $dir;
498498

499499
//split hostheader into host and port
500-
if (isset($_SERVER['HTTP_HOST'])) {
501-
if (
502-
(!empty($conf['trustedproxy'])) && isset($_SERVER['HTTP_X_FORWARDED_HOST'])
503-
&& preg_match('/' . $conf['trustedproxy'] . '/', $_SERVER['REMOTE_ADDR'])
504-
) {
505-
$cur_host = $_SERVER['HTTP_X_FORWARDED_HOST'];
506-
} else {
507-
$cur_host = $_SERVER['HTTP_HOST'];
508-
}
509-
$parsed_host = parse_url('http://' . $cur_host);
510-
$host = $parsed_host['host'] ?? '';
511-
$port = $parsed_host['port'] ?? '';
512-
} elseif (isset($_SERVER['SERVER_NAME'])) {
513-
$parsed_host = parse_url('http://' . $_SERVER['SERVER_NAME']);
514-
$host = $parsed_host['host'] ?? '';
515-
$port = $parsed_host['port'] ?? '';
516-
} else {
517-
$host = php_uname('n');
518-
$port = '';
519-
}
500+
$hostname = \dokuwiki\Ip::hostName();
501+
$parsed_host = parse_url('http://' . $hostname);
502+
$host = $parsed_host['host'] ?? '';
503+
$port = $parsed_host['port'] ?? '';
520504

521-
if (!is_ssl()) {
505+
if (!\dokuwiki\Ip::isSsl()) {
522506
$proto = 'http://';
523507
if ($port == '80') {
524508
$port = '';
@@ -536,31 +520,12 @@ function getBaseURL($abs = null)
536520
}
537521

538522
/**
539-
* Check if accessed via HTTPS
540-
*
541-
* Apache leaves ,$_SERVER['HTTPS'] empty when not available, IIS sets it to 'off'.
542-
* 'false' and 'disabled' are just guessing
543-
*
544-
* @returns bool true when SSL is active
523+
* @deprecated 2025-06-03
545524
*/
546525
function is_ssl()
547526
{
548-
global $conf;
549-
550-
// check if we are behind a reverse proxy
551-
if (
552-
(!empty($conf['trustedproxy'])) && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
553-
&& preg_match('/' . $conf['trustedproxy'] . '/', $_SERVER['REMOTE_ADDR'])
554-
&& ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
555-
) {
556-
return true;
557-
}
558-
559-
if (preg_match('/^(|off|false|disabled)$/i', $_SERVER['HTTPS'] ?? 'off')) {
560-
return false;
561-
}
562-
563-
return true;
527+
dbg_deprecated('Ip::isSsl()');
528+
return \dokuwiki\Ip::isSsl();
564529
}
565530

566531
/**

lib/exe/js.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function js_out()
103103
echo "var DOKU_TPL = '" . tpl_basedir($tpl) . "';";
104104
echo "var DOKU_COOKIE_PARAM = " . json_encode([
105105
'path' => empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'],
106-
'secure' => $conf['securecookie'] && is_ssl()
106+
'secure' => $conf['securecookie'] && \dokuwiki\Ip::isSsl(),
107107
], JSON_THROW_ON_ERROR) . ";";
108108
// FIXME: Move those to JSINFO
109109
echo "Object.defineProperty(window, 'DOKU_UHN', { get: function() {" .

0 commit comments

Comments
 (0)