diff options
author | dizzy <diosmosis@users.noreply.github.com> | 2021-02-18 01:55:26 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-18 01:55:26 +0300 |
commit | 715ded1af3cfd7d93f94fe58f5e0ecb8d8b5634c (patch) | |
tree | 289ccfb1170cbe6479446a66a0209d898b8c87ea | |
parent | 41964121548784f6e15cbe51194cf3b929be7585 (diff) |
Allow nonce checks to provide custom required referrer URL. (#17228)
* Allow checking nonce against custom referrer if needed.
* Add tests.
-rw-r--r-- | core/Nonce.php | 23 | ||||
-rw-r--r-- | tests/PHPUnit/Unit/NonceTest.php | 23 |
2 files changed, 42 insertions, 4 deletions
diff --git a/core/Nonce.php b/core/Nonce.php index ef0b09bf21..74aea105d2 100644 --- a/core/Nonce.php +++ b/core/Nonce.php @@ -65,9 +65,10 @@ class Nonce * * @param string $id The nonce's unique ID. See {@link getNonce()}. * @param string $cnonce Nonce sent from client. + * @param string $expectedReferrerHost The expected referrer host for the HTTP referrer URL. * @return bool `true` if valid; `false` otherwise. */ - public static function verifyNonce($id, $cnonce) + public static function verifyNonce($id, $cnonce, $expectedReferrerHost = null) { $ns = new SessionNamespace($id); $nonce = $ns->nonce; @@ -79,7 +80,10 @@ class Nonce // validate referrer $referrer = Url::getReferrer(); - if (!empty($referrer) && !Url::isLocalUrl($referrer)) { + if (empty($expectedReferrerHost) && !empty($referrer) && !Url::isLocalUrl($referrer)) { + return false; + } + if (!empty($expectedReferrerHost) && !self::isReferrerHostValid($referrer, $expectedReferrerHost)) { return false; } @@ -95,6 +99,17 @@ class Nonce return true; } + // public for tests + public static function isReferrerHostValid($referrer, $expectedReferrerHost) + { + if (empty($referrer)) { + return false; + } + + $referrerHost = Url::getHostFromUrl($referrer); + return preg_match('/(^|\.)' . preg_quote($expectedReferrerHost) . '$/i', $referrerHost); + } + /** * Force expiration of the current nonce. * @@ -169,13 +184,13 @@ class Nonce * **nonce** query parameter is used. * @throws \Exception if the nonce is invalid. See {@link verifyNonce()}. */ - public static function checkNonce($nonceName, $nonce = null) + public static function checkNonce($nonceName, $nonce = null, $expectedReferrerHost = null) { if ($nonce === null) { $nonce = Common::getRequestVar('nonce', null, 'string'); } - if (!self::verifyNonce($nonceName, $nonce)) { + if (!self::verifyNonce($nonceName, $nonce, $expectedReferrerHost)) { throw new \Exception(Piwik::translate('General_ExceptionNonceMismatch')); } diff --git a/tests/PHPUnit/Unit/NonceTest.php b/tests/PHPUnit/Unit/NonceTest.php index 9020257f31..00d4393b69 100644 --- a/tests/PHPUnit/Unit/NonceTest.php +++ b/tests/PHPUnit/Unit/NonceTest.php @@ -42,4 +42,27 @@ class NonceTest extends \PHPUnit\Framework\TestCase Config::getInstance()->General['trusted_hosts'] = array('example.com'); $this->assertEquals($expected, Nonce::getAcceptableOrigins(), $host); } + + /** + * @dataProvider getTestDataForIsReferrerHostValid + * @group Core + */ + public function test_isReferrerHostValid($referrer, $expectedHost, $expectedResult) + { + $result = Nonce::isReferrerHostValid($referrer, $expectedHost); + $this->assertEquals($expectedResult, $result); + } + + public function getTestDataForIsReferrerHostValid() + { + return [ + ['http://referrer.com', 'someotherreferrer.com', false], + ['http://referrer.com/referrer/path', 'referrer.com', true], + ['http://areferrer.com', 'referrer.com', false], + ['http://sub.referrer.com', 'referrer.com', true], + ['http://sub.referrer.com', 'sub.referrer.com', true], + ['http://sub.referrer.com', 'a.sub.referrer.com', false], + ['http://sub.referrer.com', 'sub2.referrer.com', false], + ]; + } } |