diff options
author | robocoder <anthon.pang@gmail.com> | 2010-03-23 21:58:32 +0300 |
---|---|---|
committer | robocoder <anthon.pang@gmail.com> | 2010-03-23 21:58:32 +0300 |
commit | 3b65a4aa7a60973f8158f4914db5c68316cf2716 (patch) | |
tree | 8b49817250f5a5055ab8f08e437c47143110f1c9 /core/Nonce.php | |
parent | 128f937253a346e422c7ae03bd453bb9bb4498c8 (diff) |
fixes #1236 - handle browser/extension/add-on causing a double page load, invalidating the token in the form; refactor Nonce class out of Piwik.php
git-svn-id: http://dev.piwik.org/svn/trunk@1981 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'core/Nonce.php')
-rw-r--r-- | core/Nonce.php | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/core/Nonce.php b/core/Nonce.php new file mode 100644 index 0000000000..44d67195f7 --- /dev/null +++ b/core/Nonce.php @@ -0,0 +1,81 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later + * @version $Id$ + * + * @category Piwik + * @package Piwik + */ + +/** + * Nonce class. + * + * A cryptographic nonce -- "number used only once" -- is often recommended as part of a robust defense against cross-site request forgery (CSRF/XSRF). + * Desrable characteristics: limited lifetime, uniqueness, unpredictability (pseudo-randomness). + * + * We use a session-dependent nonce with a configurable expiration that comines and hashes: + * - a private salt because it's non-public + * - time() because it's unique + * - a mix of PRNGs (pseudo-random number generators) to increase entropy and make it less predictable + * + * @package Piwik + */ +class Piwik_Nonce +{ + /** + * Generate nonce + * + * @param string $id Unique id to avoid namespace conflicts, e.g., ModuleName.ActionName + * @param int $ttl Optional time-to-live in seconds; default is 5 minutes + * @return string Nonce + */ + static public function getNonce($id, $ttl = 300) + { + // save session-dependent nonce + $ns = new Zend_Session_Namespace($id); + $nonce = $ns->nonce; + + // re-use an unexpired nonce (a small deviation from the "used only once" principle, so long as we do not reset the expiration) + // to handle browser pre-fetch or double fetch caused by some browser add-ons/extensions + if(empty($nonce)) + { + // generate a new nonce + $nonce = md5(Piwik_Common::getSalt() . time() . Piwik_Common::generateUniqId()); + $ns->nonce = $nonce; + $ns->setExpirationSeconds($ttl, 'nonce'); + } + + return $nonce; + } + + /** + * Verify nonce and check referrer (if present, i.e., it may be suppressed by the browser or a proxy/network). + * + * @param string $id Unique id + * @param string $cnonce Nonce sent to client + * @return bool true if valid; false otherwise + */ + static public function verifyNonce($id, $cnonce) + { + $ns = new Zend_Session_Namespace($id); + $nonce = $ns->nonce; + + // validate token + if(empty($cnonce) || $cnonce !== $nonce) + { + return false; + } + + // validate referer + $referer = Piwik_Url::getReferer(); + if(!empty($referer) && (Piwik_Url::getLocalReferer() === false)) + { + return false; + } + + return true; + } +} |