diff --git a/lib/base.php b/lib/base.php index 351b91b7df..82612a1877 100644 --- a/lib/base.php +++ b/lib/base.php @@ -694,6 +694,22 @@ class OC { exit(); } + $host = OC_Request::insecureServerHost(); + // if the host passed in headers isn't trusted + if (!OC::$CLI + // overwritehost is always trusted + && OC_Request::getOverwriteHost() === null + && !OC_Request::isTrustedDomain($host)) { + + header('HTTP/1.1 400 Bad Request'); + header('Status: 400 Bad Request'); + OC_Template::printErrorPage( + 'You are accessing the server from an untrusted domain.', + 'Please contact your administrator' + ); + return; + } + $request = OC_Request::getPathInfo(); if (substr($request, -3) !== '.js') { // we need these files during the upgrade self::checkMaintenanceMode(); diff --git a/lib/private/request.php b/lib/private/request.php index afd3fda4f2..fb387e83e3 100755 --- a/lib/private/request.php +++ b/lib/private/request.php @@ -25,17 +25,64 @@ class OC_Request { } /** - * @brief Checks whether a domain is considered as trusted. This is used to prevent Host Header Poisoning. + * @brief Checks whether a domain is considered as trusted from the list + * of trusted domains. If no trusted domains have been configured, returns + * true. + * This is used to prevent Host Header Poisoning. * @param string $host - * @return bool + * @return bool true if the given domain is trusted or if no trusted domains + * have been configured */ public static function isTrustedDomain($domain) { - $trustedList = \OC_Config::getValue('trusted_domains', array('')); + $trustedList = \OC_Config::getValue('trusted_domains', array()); + if (empty($trustedList)) { + return true; + } return in_array($domain, $trustedList); } /** - * @brief Returns the server host + * @brief Returns the unverified server host from the headers without checking + * whether it is a trusted domain + * @returns string the server host + * + * Returns the server host, even if the website uses one or more + * reverse proxies + */ + public static function insecureServerHost() { + $host = null; + if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { + if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { + $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); + } else { + $host = $_SERVER['HTTP_X_FORWARDED_HOST']; + } + } else { + if (isset($_SERVER['HTTP_HOST'])) { + $host = $_SERVER['HTTP_HOST']; + } else if (isset($_SERVER['SERVER_NAME'])) { + $host = $_SERVER['SERVER_NAME']; + } + } + return $host; + } + + /** + * Returns the overwritehost setting from the config if set and + * if the overwrite condition is met + * @return overwritehost value or null if not defined or the defined condition + * isn't met + */ + public static function getOverwriteHost() { + if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { + return OC_Config::getValue('overwritehost'); + } + return null; + } + + /** + * @brief Returns the server host from the headers, or the first configured + * trusted domain if the host isn't in the trusted list * @returns string the server host * * Returns the server host, even if the website uses one or more @@ -45,29 +92,20 @@ class OC_Request { if(OC::$CLI) { return 'localhost'; } - if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) { - return OC_Config::getValue('overwritehost'); - } - if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { - if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) { - $host = trim(array_pop(explode(",", $_SERVER['HTTP_X_FORWARDED_HOST']))); - } - else{ - $host = $_SERVER['HTTP_X_FORWARDED_HOST']; - } - } else { - if (isset($_SERVER['HTTP_HOST'])) { - $host = $_SERVER['HTTP_HOST']; - } - else if (isset($_SERVER['SERVER_NAME'])) { - $host = $_SERVER['SERVER_NAME']; - } + + // overwritehost is always trusted + $host = self::getOverwriteHost(); + if ($host !== null) { + return $host; } + // get the host from the headers + $host = self::insecureServerHost(); + // Verify that the host is a trusted domain if the trusted domains // are defined // If no trusted domain is provided the first trusted domain is returned - if(self::isTrustedDomain($host) || \OC_Config::getValue('trusted_domains', "") === "") { + if (self::isTrustedDomain($host)) { return $host; } else { $trustedList = \OC_Config::getValue('trusted_domains', array(''));