Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions config/config.sample.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@
* Your list of trusted domains that users can log into. Specifying trusted
* domains prevents host header poisoning. Do not remove this, as it performs
* necessary security checks.
* You can specify:
* - the exact hostname of your host or virtual host, e.g. demo.example.org.
* - the exact hostname with permitted port, e.g. demo.example.org:443.
* This disallows all other ports on this host
* - use * as a wildcard, e.g. ubos-raspberry-pi*.local will allow
* ubos-raspberry-pi.local and ubos-raspberry-pi-2.local
*/
'trusted_domains' =>
array (
Expand Down
23 changes: 15 additions & 8 deletions lib/private/Security/TrustedDomainHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,28 @@ public function isTrustedDomain($domainWithPort) {

// Read trusted domains from config
$trustedList = $this->config->getSystemValue('trusted_domains', []);
if(!is_array($trustedList)) {
if (!is_array($trustedList)) {
return false;
}

// Always allow access from localhost
if (preg_match(Request::REGEX_LOCALHOST, $domain) === 1) {
return true;
}

// Compare with port appended
if(in_array($domainWithPort, $trustedList, true)) {
return true;
// Reject misformed domains in any case
if (strpos($domain,'-') === 0 || strpos($domain,'..') !== false) {
return false;
}

return in_array($domain, $trustedList, true);
// Match, allowing for * wildcards
foreach ($trustedList as $trusted) {
if (gettype($trusted) !== 'string') {
break;
}
$regex = '/^' . join('[-\.a-zA-Z0-9]*', array_map(function($v) { return preg_quote($v, '/'); }, explode('*', $trusted))) . '$/';
if (preg_match($regex, $domain) || preg_match($regex, $domainWithPort)) {
return true;
}
}
return false;
}

}
31 changes: 30 additions & 1 deletion tests/lib/Security/TrustedDomainHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public function trustedDomainDataProvider() {
'host.two.test',
'[1fff:0:a88:85a3::ac1f]',
'host.three.test:443',
'*.leading.host',
'trailing.host*',
'cen*ter',
'*.leadingwith.port:123',
'trailingwith.port*:456',
];
return [
// empty defaults to false with 8.1
Expand Down Expand Up @@ -76,7 +81,31 @@ public function trustedDomainDataProvider() {
[$trustedHostTestList, 'localhost: evil.host', false],
// do not trust casting
[[1], '1', false],
// leading *
[$trustedHostTestList, 'abc.leading.host', true],
[$trustedHostTestList, 'abc.def.leading.host', true],
[$trustedHostTestList, 'abc.def.leading.host.another', false],
[$trustedHostTestList, 'abc.def.leading.host:123', true],
[$trustedHostTestList, 'leading.host', false],
// trailing *
[$trustedHostTestList, 'trailing.host', true],
[$trustedHostTestList, 'trailing.host.abc', true],
[$trustedHostTestList, 'trailing.host.abc.def', true],
[$trustedHostTestList, 'trailing.host.abc:123', true],
[$trustedHostTestList, 'another.trailing.host', false],
// center *
[$trustedHostTestList, 'center', true],
[$trustedHostTestList, 'cenxxxter', true],
[$trustedHostTestList, 'cen.x.y.ter', true],
// with port
[$trustedHostTestList, 'abc.leadingwith.port:123', true],
[$trustedHostTestList, 'abc.leadingwith.port:1234', false],
[$trustedHostTestList, 'trailingwith.port.abc:456', true],
[$trustedHostTestList, 'trailingwith.port.abc:123', false],
// bad hostname
[$trustedHostTestList, '-bad', false],
[$trustedHostTestList, '-bad.leading.host', false],
[$trustedHostTestList, 'bad..der.leading.host', false],
];
}

}