|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2010-2011 Oliver Klee <typo3-coding@oliverklee.de> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * 00017 * This script is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 * GNU General Public License for more details. 00021 * 00022 * This copyright notice MUST APPEAR in all copies of the script! 00023 ***************************************************************/ 00024 00025 /** 00026 * Class t3lib_formprotection_Abstract. 00027 * 00028 * This class provides protection against cross-site request forgery (XSRF/CSRF) 00029 * for forms. 00030 * 00031 * For documentation on how to use this class, please see the documentation of 00032 * the corresponding subclasses, e.g. t3lib_formprotection_BackendFormProtection. 00033 * 00034 * $Id$ 00035 * 00036 * @package TYPO3 00037 * @subpackage t3lib 00038 * 00039 * @author Oliver Klee <typo3-coding@oliverklee.de> 00040 */ 00041 abstract class t3lib_formprotection_Abstract { 00042 /** 00043 * the maximum number of tokens that can exist at the same time 00044 * 00045 * @var integer 00046 */ 00047 protected $maximumNumberOfTokens = 0; 00048 00049 /** 00050 * Valid tokens sorted from oldest to newest. 00051 * 00052 * [tokenId] => array(formName, formInstanceName) 00053 * 00054 * @var array<array> 00055 */ 00056 protected $tokens = array(); 00057 00058 /** 00059 * Tokens that have been added during this request. 00060 * 00061 * @var array<array> 00062 */ 00063 protected $addedTokens = array(); 00064 00065 /** 00066 * Token ids of tokens that have been dropped during this request. 00067 * 00068 * @var array 00069 */ 00070 protected $droppedTokenIds = array(); 00071 00072 /** 00073 * Constructor. Makes sure existing tokens are read and available for 00074 * checking. 00075 */ 00076 public function __construct() { 00077 $this->tokens = $this->retrieveTokens(); 00078 } 00079 00080 /** 00081 * Frees as much memory as possible. 00082 */ 00083 public function __destruct() { 00084 $this->tokens = array(); 00085 } 00086 00087 /** 00088 * Deletes all existing tokens and persists the (empty) token table. 00089 * 00090 * This function is intended to be called when a user logs on or off. 00091 * 00092 * @return void 00093 */ 00094 public function clean() { 00095 $this->tokens = array(); 00096 $this->persistTokens(); 00097 } 00098 00099 /** 00100 * Generates and stores a token for a form. 00101 * 00102 * Calling this function two times with the same parameters will create 00103 * two valid, different tokens. 00104 * 00105 * Generating more tokens than $maximumNumberOfEntries will cause the oldest 00106 * tokens to get dropped. 00107 * 00108 * Note: This function does not persist the tokens. 00109 * 00110 * @param string $formName 00111 * the name of the form, for example a table name like "tt_content", 00112 * or some other identifier like "install_tool_password", must not be 00113 * empty 00114 * @param string $action 00115 * the name of the action of the form, for example "new", "delete" or 00116 * "edit", may also be empty 00117 * @param string $formInstanceName 00118 * a string used to differentiate two instances of the same form, 00119 * form example a record UID or a comma-separated list of UIDs, 00120 * may also be empty 00121 * 00122 * @return string the 32-character hex ID of the generated token 00123 */ 00124 public function generateToken( 00125 $formName, $action = '', $formInstanceName = '' 00126 ) { 00127 if ($formName == '') { 00128 throw new InvalidArgumentException('$formName must not be empty.'); 00129 } 00130 00131 do { 00132 $tokenId = bin2hex(t3lib_div::generateRandomBytes(16)); 00133 } while (isset($this->tokens[$tokenId])); 00134 00135 $this->tokens[$tokenId] = array( 00136 'formName' => $formName, 00137 'action' => $action, 00138 'formInstanceName' => $formInstanceName, 00139 ); 00140 $this->addedTokens[$tokenId] = $this->tokens[$tokenId]; 00141 $this->preventOverflow(); 00142 00143 return $tokenId; 00144 } 00145 00146 /** 00147 * Checks whether the token $tokenId is valid in the form $formName with 00148 * $formInstanceName. 00149 * 00150 * A token is valid if $tokenId, $formName and $formInstanceName match and 00151 * the token has not been used yet. 00152 * 00153 * Calling this function will mark the token $tokenId as invalud (if it 00154 * exists). 00155 * 00156 * So calling this function with the same parameters two times will return 00157 * FALSE the second time. 00158 * 00159 * @param string $tokenId 00160 * a form token to check, may also be empty or utterly misformed 00161 * @param string $formName 00162 * the name of the form to check, for example "tt_content", 00163 * may also be empty or utterly misformed 00164 * @param string $action 00165 * the action of the form to check, for example "edit", 00166 * may also be empty or utterly misformed 00167 * @param string $formInstanceName 00168 * the instance name of the form to check, for example "42" or "foo" 00169 * or "31,42", may also be empty or utterly misformed 00170 * 00171 * @return boolean 00172 * TRUE if $tokenId, $formName, $action and $formInstanceName match 00173 * and the token has not been used yet, FALSE otherwise 00174 */ 00175 public function validateToken( 00176 $tokenId, $formName, $action = '', $formInstanceName = '' 00177 ) { 00178 if (isset($this->tokens[$tokenId])) { 00179 $token = $this->tokens[$tokenId]; 00180 $isValid = ($token['formName'] == $formName) 00181 && ($token['action'] == $action) 00182 && ($token['formInstanceName'] == $formInstanceName); 00183 $this->dropToken($tokenId); 00184 } else { 00185 $isValid = FALSE; 00186 } 00187 00188 if (!$isValid) { 00189 $this->createValidationErrorMessage(); 00190 } 00191 00192 return $isValid; 00193 } 00194 00195 /** 00196 * Creates or displayes an error message telling the user that the submitted 00197 * form token is invalid. 00198 * 00199 * This function may also be empty if the validation error should be handled 00200 * silently. 00201 * 00202 * @return void 00203 */ 00204 abstract protected function createValidationErrorMessage(); 00205 00206 /** 00207 * Retrieves all saved tokens. 00208 * 00209 * @return array<arrray> 00210 * the saved tokens, will be empty if no tokens have been saved 00211 */ 00212 abstract protected function retrieveTokens(); 00213 00214 /** 00215 * Saves the tokens so that they can be used by a later incarnation of this 00216 * class. 00217 * 00218 * @return void 00219 */ 00220 abstract public function persistTokens(); 00221 00222 /** 00223 * Drops the token with the ID $tokenId. 00224 * 00225 * If there is no token with that ID, this function is a no-op. 00226 * 00227 * Note: This function does not persist the tokens. 00228 * 00229 * @param string $tokenId 00230 * the 32-character ID of an existing token, must not be empty 00231 * 00232 * @return void 00233 */ 00234 protected function dropToken($tokenId) { 00235 if (isset($this->tokens[$tokenId])) { 00236 unset($this->tokens[$tokenId]); 00237 $this->droppedTokenIds[] = $tokenId; 00238 } 00239 } 00240 00241 /** 00242 * Persisting of tokens is only required, if tokens are 00243 * deleted or added during this request. 00244 * 00245 * @return boolean 00246 */ 00247 protected function isPersistingRequired() { 00248 return !empty($this->droppedTokenIds) || !empty($this->addedTokens); 00249 } 00250 00251 /** 00252 * Reset the arrays of added or deleted tokens. 00253 * 00254 * @return void 00255 */ 00256 protected function resetPersistingRequiredStatus() { 00257 $this->droppedTokenIds = array(); 00258 $this->addedTokens = array(); 00259 } 00260 00261 /** 00262 * Checks whether the number of current tokens still is at most 00263 * $this->maximumNumberOfTokens. 00264 * 00265 * If there are more tokens, the oldest tokens are removed until the number 00266 * of tokens is low enough. 00267 * 00268 * Note: This function does not persist the tokens. 00269 * 00270 * @return void 00271 */ 00272 protected function preventOverflow() { 00273 if (empty($this->tokens)) { 00274 return; 00275 } 00276 00277 while (count($this->tokens) > $this->maximumNumberOfTokens) { 00278 reset($this->tokens); 00279 $this->dropToken(key($this->tokens)); 00280 } 00281 } 00282 } 00283 00284 ?>
1.8.0