PageRenderTime 54ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/class/xoopssecurity.php

https://gitlab.com/VoyaTrax/vtCMS2
PHP | 285 lines | 157 code | 19 blank | 109 comment | 30 complexity | 3c792f94c51eb3e64529cac9d29f7ae8 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, MIT, GPL-3.0, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * XOOPS security handler
  4. *
  5. * You may not change or alter any portion of this comment or credits
  6. * of supporting developers from this source code or any supporting source code
  7. * which is considered copyrighted (c) material of the original comment or credit authors.
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. *
  12. * @author Kazumi Ono <onokazu@xoops.org>
  13. * @author Jan Pedersen <mithrandir@xoops.org>
  14. * @author John Neill <catzwolf@xoops.org>
  15. * @copyright (c) 2000-2016 XOOPS Project (www.xoops.org)
  16. * @license GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
  17. * @package kernel
  18. * @since 2.0.0
  19. */
  20. defined('XOOPS_ROOT_PATH') || exit('Restricted access');
  21. /**
  22. * Class XoopsSecurity
  23. */
  24. class XoopsSecurity
  25. {
  26. public $errors = array();
  27. /**
  28. * Check if there is a valid token in $_REQUEST[$name . '_REQUEST'] - can be expanded for more wide use, later (Mith)
  29. *
  30. * @param bool $clearIfValid whether to clear the token after validation
  31. * @param string|false $token token to validate
  32. * @param string $name name of session variable
  33. *
  34. * @return bool
  35. */
  36. public function check($clearIfValid = true, $token = false, $name = 'XOOPS_TOKEN')
  37. {
  38. return $this->validateToken($token, $clearIfValid, $name);
  39. }
  40. /**
  41. * Create a token in the user's session
  42. *
  43. * @param int $timeout time in seconds the token should be valid
  44. * @param string $name name of session variable
  45. *
  46. * @return string token value
  47. */
  48. public function createToken($timeout = 0, $name = 'XOOPS_TOKEN')
  49. {
  50. $this->garbageCollection($name);
  51. if ($timeout == 0) {
  52. $expire = @ini_get('session.gc_maxlifetime');
  53. $timeout = ($expire > 0) ? $expire : 900;
  54. }
  55. $token_id = md5(uniqid(mt_rand(), true));
  56. // save token data on the server
  57. if (!isset($_SESSION[$name . '_SESSION'])) {
  58. $_SESSION[$name . '_SESSION'] = array();
  59. }
  60. $token_data = array(
  61. 'id' => $token_id,
  62. 'expire' => time() + (int)$timeout);
  63. $_SESSION[$name . '_SESSION'][] = $token_data;
  64. return md5($token_id . $_SERVER['HTTP_USER_AGENT'] . XOOPS_DB_PREFIX);
  65. }
  66. /**
  67. * Check if a token is valid. If no token is specified, $_REQUEST[$name . '_REQUEST'] is checked
  68. *
  69. * @param string|false $token token to validate
  70. * @param bool $clearIfValid whether to clear the token value if valid
  71. * @param string $name session name to validate
  72. *
  73. * @return bool
  74. */
  75. public function validateToken($token = false, $clearIfValid = true, $name = 'XOOPS_TOKEN')
  76. {
  77. global $xoopsLogger;
  78. $token = ($token !== false) ? $token : (isset($_REQUEST[$name . '_REQUEST']) ? $_REQUEST[$name . '_REQUEST'] : '');
  79. if (empty($token) || empty($_SESSION[$name . '_SESSION'])) {
  80. $xoopsLogger->addExtra('Token Validation', 'No valid token found in request/session');
  81. return false;
  82. }
  83. $validFound = false;
  84. $token_data = &$_SESSION[$name . '_SESSION'];
  85. foreach (array_keys($token_data) as $i) {
  86. if ($token === md5($token_data[$i]['id'] . $_SERVER['HTTP_USER_AGENT'] . XOOPS_DB_PREFIX)) {
  87. if ($this->filterToken($token_data[$i])) {
  88. if ($clearIfValid) {
  89. // token should be valid once, so clear it once validated
  90. unset($token_data[$i]);
  91. }
  92. $xoopsLogger->addExtra('Token Validation', 'Valid token found');
  93. $validFound = true;
  94. } else {
  95. $str = 'Valid token expired';
  96. $this->setErrors($str);
  97. $xoopsLogger->addExtra('Token Validation', $str);
  98. }
  99. }
  100. }
  101. if (!$validFound && !isset($str)) {
  102. $str = 'No valid token found';
  103. $this->setErrors($str);
  104. $xoopsLogger->addExtra('Token Validation', $str);
  105. }
  106. $this->garbageCollection($name);
  107. return $validFound;
  108. }
  109. /**
  110. * Clear all token values from user's session
  111. *
  112. * @param string $name session name
  113. *
  114. * @return void
  115. */
  116. public function clearTokens($name = 'XOOPS_TOKEN')
  117. {
  118. $_SESSION[$name . '_SESSION'] = array();
  119. }
  120. /**
  121. * Check whether a token value is expired or not
  122. *
  123. * @param string $token token
  124. *
  125. * @return bool
  126. */
  127. public function filterToken($token)
  128. {
  129. return (!empty($token['expire']) && $token['expire'] >= time());
  130. }
  131. /**
  132. * Perform garbage collection, clearing expired tokens
  133. *
  134. * @param string $name session name
  135. *
  136. * @return void
  137. */
  138. public function garbageCollection($name = 'XOOPS_TOKEN')
  139. {
  140. $sessionName = $name . '_SESSION';
  141. if (!empty($_SESSION[$sessionName]) && is_array($_SESSION[$sessionName])) {
  142. $_SESSION[$sessionName] = array_filter($_SESSION[$sessionName], array($this, 'filterToken'));
  143. }
  144. }
  145. /**
  146. * Check the user agent's HTTP REFERER against XOOPS_URL
  147. *
  148. * @param int $docheck 0 to not check the referer (used with XML-RPC), 1 to actively check it
  149. *
  150. * @return bool
  151. */
  152. public function checkReferer($docheck = 1)
  153. {
  154. $ref = xoops_getenv('HTTP_REFERER');
  155. if ($docheck == 0) {
  156. return true;
  157. }
  158. if ($ref == '') {
  159. return false;
  160. }
  161. return !(strpos($ref, XOOPS_URL) !== 0);
  162. }
  163. /**
  164. * Check superglobals for contamination
  165. *
  166. * @return void
  167. **/
  168. public function checkSuperglobals()
  169. {
  170. foreach (array(
  171. 'GLOBALS',
  172. '_SESSION',
  173. 'HTTP_SESSION_VARS',
  174. '_GET',
  175. 'HTTP_GET_VARS',
  176. '_POST',
  177. 'HTTP_POST_VARS',
  178. '_COOKIE',
  179. 'HTTP_COOKIE_VARS',
  180. '_REQUEST',
  181. '_SERVER',
  182. 'HTTP_SERVER_VARS',
  183. '_ENV',
  184. 'HTTP_ENV_VARS',
  185. '_FILES',
  186. 'HTTP_POST_FILES',
  187. 'xoopsDB',
  188. 'xoopsUser',
  189. 'xoopsUserId',
  190. 'xoopsUserGroups',
  191. 'xoopsUserIsAdmin',
  192. 'xoopsConfig',
  193. 'xoopsOption',
  194. 'xoopsModule',
  195. 'xoopsModuleConfig',
  196. 'xoopsRequestUri') as $bad_global) {
  197. if (isset($_REQUEST[$bad_global])) {
  198. header('Location: ' . XOOPS_URL . '/');
  199. exit();
  200. }
  201. }
  202. }
  203. /**
  204. * Check if visitor's IP address is banned
  205. * Should be changed to return bool and let the action be up to the calling script
  206. *
  207. * @return void
  208. */
  209. public function checkBadips()
  210. {
  211. global $xoopsConfig;
  212. if ($xoopsConfig['enable_badips'] == 1 && isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != '') {
  213. foreach ($xoopsConfig['bad_ips'] as $bi) {
  214. if (!empty($bi) && preg_match('/' . $bi . '/', $_SERVER['REMOTE_ADDR'])) {
  215. exit();
  216. }
  217. }
  218. }
  219. unset($bi, $bad_ips, $xoopsConfig['badips']);
  220. }
  221. /**
  222. * Get the HTML code for a XoopsFormHiddenToken object - used in forms that do not use XoopsForm elements
  223. *
  224. * @param string $name session token name
  225. *
  226. * @return string
  227. */
  228. public function getTokenHTML($name = 'XOOPS_TOKEN')
  229. {
  230. require_once XOOPS_ROOT_PATH . '/class/xoopsformloader.php';
  231. $token = new XoopsFormHiddenToken($name);
  232. return $token->render();
  233. }
  234. /**
  235. * Add an error
  236. *
  237. * @param string $error message
  238. *
  239. * @return void
  240. */
  241. public function setErrors($error)
  242. {
  243. $this->errors[] = trim($error);
  244. }
  245. /**
  246. * Get generated errors
  247. *
  248. * @param bool $ashtml Format using HTML?
  249. *
  250. * @return array|string Array of array messages OR HTML string
  251. */
  252. public function &getErrors($ashtml = false)
  253. {
  254. if (!$ashtml) {
  255. return $this->errors;
  256. } else {
  257. $ret = '';
  258. if (count($this->errors) > 0) {
  259. foreach ($this->errors as $error) {
  260. $ret .= $error . '<br />';
  261. }
  262. }
  263. return $ret;
  264. }
  265. }
  266. }