diff options
author | petko <petko@524c5546-5005-0410-9a3e-e25e191bd360> | 2023-04-28 09:04:59 +0000 |
---|---|---|
committer | petko <petko@524c5546-5005-0410-9a3e-e25e191bd360> | 2023-04-28 09:04:59 +0000 |
commit | c87c43fd1815ebccacd79d559d8e3cdaa59f1ccb (patch) | |
tree | 86a97799cc87cf70df8b5778bb9f73d30440accb /pmwiki.php | |
parent | fba6096db3b8979409ae715836bb01831021de3d (diff) | |
download | pmwiki.svn-c87c43fd1815ebccacd79d559d8e3cdaa59f1ccb.tar.bz2 |
Refactor pmtoken() to use session tokens, enable for core actions.
git-svn-id: svn://pmwiki.org/pmwiki/trunk@4435 524c5546-5005-0410-9a3e-e25e191bd360
Diffstat (limited to 'pmwiki.php')
-rw-r--r-- | pmwiki.php | 111 |
1 files changed, 43 insertions, 68 deletions
@@ -71,7 +71,7 @@ $TimeISOZFmt = '%Y-%m-%dT%H:%M:%SZ'; $MessagesFmt = array(); $BlockMessageFmt = "<h3 class='wikimessage'>$[This post has been blocked by the administrator]</h3>"; $EditFields = array('text'); -$EditFunctions = array('AutoCheckToken', 'EditTemplate', 'RestorePage', 'ReplaceOnSave', +$EditFunctions = array('EditTemplate', 'RestorePage', 'ReplaceOnSave', 'SaveAttributes', 'PostPage', 'PostRecentChanges', 'AutoCreateTargets', 'PreviewPage'); $EnablePost = 1; @@ -856,36 +856,40 @@ function pmcrypt($str, $salt=null) { return crypt($str); } -# generate or check a random one-time token to prevent CSRF -function pmtoken($token = null) { - global $SessionMaxTokens, $PmTokenFn; +# generate or check a random session token to prevent CSRF +# 0=get/set token, 1=check $_POST, 2=check $_GET, +# 3=check $_COOKIE, -3=set $_COOKIE +function pmtoken($check = 0, $abort = 0) { + global $EnablePmToken, $PmTokenFn, $FmtV, $InputValues; + static $called = 0, $cookie = 0; + if (IsEnabled($PmTokenFn) && function_exists($PmTokenFn)) return $PmTokenFn($token); + + if (! IsEnabled($EnablePmToken, 1)) return true; pm_session_start(); - if (!isset($_SESSION['pmtokens'])) $_SESSION['pmtokens'] = array(); - if (is_null($token)) { # create a one-time token - $len = mt_rand(20,30); - $token = ""; - while(strlen($token)<$len) { - $token .= chr(mt_rand(32,126)); - } - if (count($_SESSION['pmtokens'])) - $id = max(array_keys($_SESSION['pmtokens']))+1; - else $id = 0; - $_SESSION['pmtokens'][$id] = $token; - if (IsEnabled($SessionMaxTokens, 0)) { - $max = $SessionMaxTokens; - $_SESSION['pmtokens'] = array_slice($_SESSION['pmtokens'], -$max, $max, true); - } - return "$id:" . md5($token); + $key = $FmtV['$TokenName']; + + if (!isset($_SESSION['pmtoken'])) { + $token = $_SESSION['pmtoken'] = PmNonce().PmNonce(); } - # else: check a token, if correct, delete it - @list($id, $hash) = explode(':', $token); - $id = intval($id); - if (isset($_SESSION['pmtokens'][$id]) && $hash == md5($_SESSION['pmtokens'][$id])) { - unset($_SESSION['pmtokens'][$id]); - return true; + else $token = $_SESSION['pmtoken']; + + if (! $called++) { + $InputValues[$key] = $FmtV['$TokenValue'] = $token; + } + if ($check == -3 && !$cookie++) pmsetcookie($key, $token); + + if ($check <= 0) { # get the token + return $token; } + # else: check the token + if ($check === 1 && $token === @$_POST[$key]) return true; + elseif ($check === 2 && $token === @$_GET[$key]) return true; + elseif ($check === 3 && $token === @$_COOKIE[$key]) return true; + + # fail + if ($abort) Abort('? $[Token invalid or missing.]'); return false; } @@ -893,12 +897,10 @@ function PmNonce() { if (function_exists('random_bytes')) { $nonce = bin2hex(random_bytes(5)); } - else $nonce = mt_rand(); + else $nonce = 'x'.mt_rand().mt_rand(); return $nonce; } - - function StopWatch($x) { global $StopWatch, $EnableStopWatch; if (!$EnableStopWatch) return; @@ -1613,7 +1615,14 @@ class PageStore { return ($pagefile && file_exists($pagefile)); } function delete($pagename) { - global $Now, $PageExistsCache; + global $Now, $PageExistsCache, $TrashNameFmt; + if(IsEnabled($TrashNameFmt,0)) { + $tn = FmtPageName($TrashNameFmt, $pagename); + if(strpos($tn, '%')!==false) $tn = PSFT($tn, $Now); + $tn = MakePageName($pagename, $tn); + $page = $this->read($pagename); + $this->write($tn,$page); + } $pagefile = $this->pagefile($pagename); @rename($pagefile,"$pagefile,del-$Now"); unset($PageExistsCache[$pagename]); # PITS:01401 @@ -2438,39 +2447,6 @@ function UpdatePage(&$pagename, &$page, &$new, $fnlist = NULL) { return $IsPagePosted; } -# AutoCheckToken verifies if the posted content was sent -# from the website forms, to prevent CSRF -function AutoCheckToken() { - # TODO: Work in progress (Jan 2021), releasing for - return true; - - global $EnablePost, $AutoCheckTokenActions, $EnablePmToken, - $FmtV, $action, $BlockMessageFmt, $MessagesFmt; - - # a quick way to disable tokens - if (! IsEnabled($EnablePmToken, 1)) return true; - - SDVA($AutoCheckTokenActions, array( # 1=POST, 2=GET, 0=disabled - 'edit' => 1, - 'postattr' => 1, - 'postupload' => 1, - 'approvesites' => 2, - 'approveurls' => 2, - )); - $tname = $FmtV['$TokenName']; - $x = @$AutoCheckTokenActions[$action]; - if (!$x) return true; - elseif ($x==1) { - if ( count($_POST) < 1 || pmtoken(''.@$_POST[$tname]) ) return true; - } - elseif ($x==2 && pmtoken(''.@$_GET[$tname])) return true; - - $EnablePost = 0; - $MessagesFmt[] = $BlockMessageFmt; - $MessagesFmt[] = XL('Token invalid or missing.'); - return false; -} - # EditTemplate allows a site administrator to pre-populate new pages # with the contents of another page. function EditTemplate($pagename, &$page, &$new) { @@ -2695,6 +2671,7 @@ function HandleEdit($pagename, $auth = 'edit') { $new['csum'] = $ChangeSummary; if ($ChangeSummary) $new["csum:$Now"] = $ChangeSummary; $EnablePost &= (bool)preg_grep('/^post/', array_keys(@$_POST)); + if($EnablePost) pmtoken(1, true); $new['=preview'] = @$new['text']; PCache($pagename, $new); UpdatePage($pagename, $page, $new); @@ -2706,7 +2683,7 @@ function HandleEdit($pagename, $auth = 'edit') { $FmtV['$EditText'] = str_replace('$','$',PHSC(@$new['text'],ENT_NOQUOTES)); $FmtV['$EditBaseTime'] = $Now; - $FmtV['$TokenValue'] = pmtoken(); + pmtoken(); if (@$PageEditForm) { $efpage = FmtPageName($PageEditForm, $pagename); $form = RetrieveAuthPage($efpage, 'read', false, READPAGE_CURRENT); @@ -2935,7 +2912,7 @@ function PasswdVar($pagename, $level) { function PrintAttrForm($pagename) { global $PageAttributes, $PCache, $FmtV; - $FmtV['$TokenValue'] = pmtoken(); + pmtoken(); echo FmtPageName("<form action='\$PageUrl' method='post'> <input type='hidden' name='action' value='postattr' /> <input type='hidden' name='\$TokenName' value='\$TokenValue' /> @@ -2976,9 +2953,7 @@ function HandleAttr($pagename, $auth = 'attr') { function HandlePostAttr($pagename, $auth = 'attr') { global $PageAttributes, $EnablePostAttrClearSession; - if (! AutoCheckToken()) { - Abort('? $[Token invalid or missing.]'); - } + pmtoken(1, true); Lock(2); $page = RetrieveAuthPage($pagename, $auth, true); if (!$page) { Abort("?unable to read $pagename"); } |