PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/system/core/Security.php

https://bitbucket.org/hlevine/myclientbase-south-african-version
PHP | 866 lines | 663 code | 37 blank | 166 comment | 13 complexity | 5d70ebb20dce267c125091b36397f4a6 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author ExpressionEngine Dev Team
  9. * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc.
  10. * @license http://codeigniter.com/user_guide/license.html
  11. * @link http://codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * Security Class
  18. *
  19. * @package CodeIgniter
  20. * @subpackage Libraries
  21. * @category Security
  22. * @author ExpressionEngine Dev Team
  23. * @link http://codeigniter.com/user_guide/libraries/security.html
  24. */
  25. class CI_Security {
  26. /**
  27. * Random Hash for protecting URLs
  28. *
  29. * @var string
  30. * @access protected
  31. */
  32. protected $_xss_hash = '';
  33. /**
  34. * Random Hash for Cross Site Request Forgery Protection Cookie
  35. *
  36. * @var string
  37. * @access protected
  38. */
  39. protected $_csrf_hash = '';
  40. /**
  41. * Expiration time for Cross Site Request Forgery Protection Cookie
  42. * Defaults to two hours (in seconds)
  43. *
  44. * @var int
  45. * @access protected
  46. */
  47. protected $_csrf_expire = 7200;
  48. /**
  49. * Token name for Cross Site Request Forgery Protection Cookie
  50. *
  51. * @var string
  52. * @access protected
  53. */
  54. protected $_csrf_token_name = 'ci_csrf_token';
  55. /**
  56. * Cookie name for Cross Site Request Forgery Protection Cookie
  57. *
  58. * @var string
  59. * @access protected
  60. */
  61. protected $_csrf_cookie_name = 'ci_csrf_token';
  62. /**
  63. * List of never allowed strings
  64. *
  65. * @var array
  66. * @access protected
  67. */
  68. protected $_never_allowed_str = array(
  69. 'document.cookie' => '[removed]',
  70. 'document.write' => '[removed]',
  71. '.parentNode' => '[removed]',
  72. '.innerHTML' => '[removed]',
  73. 'window.location' => '[removed]',
  74. '-moz-binding' => '[removed]',
  75. '<!--' => '&lt;!--',
  76. '-->' => '--&gt;',
  77. '<![CDATA[' => '&lt;![CDATA[',
  78. '<comment>' => '&lt;comment&gt;'
  79. );
  80. /* never allowed, regex replacement */
  81. /**
  82. * List of never allowed regex replacement
  83. *
  84. * @var array
  85. * @access protected
  86. */
  87. protected $_never_allowed_regex = array(
  88. "javascript\s*:" => '[removed]',
  89. "expression\s*(\(|&\#40;)" => '[removed]', // CSS and IE
  90. "vbscript\s*:" => '[removed]', // IE, surprise!
  91. "Redirect\s+302" => '[removed]'
  92. );
  93. /**
  94. * Constructor
  95. */
  96. public function __construct()
  97. {
  98. // CSRF config
  99. foreach(array('csrf_expire', 'csrf_token_name', 'csrf_cookie_name') as $key)
  100. {
  101. if (FALSE !== ($val = config_item($key)))
  102. {
  103. $this->{'_'.$key} = $val;
  104. }
  105. }
  106. // Append application specific cookie prefix
  107. if (config_item('cookie_prefix'))
  108. {
  109. $this->_csrf_cookie_name = config_item('cookie_prefix').$this->_csrf_cookie_name;
  110. }
  111. // Set the CSRF hash
  112. $this->_csrf_set_hash();
  113. log_message('debug', "Security Class Initialized");
  114. }
  115. // --------------------------------------------------------------------
  116. /**
  117. * Verify Cross Site Request Forgery Protection
  118. *
  119. * @return object
  120. */
  121. public function csrf_verify()
  122. {
  123. // If no POST data exists we will set the CSRF cookie
  124. if (count($_POST) == 0)
  125. {
  126. return $this->csrf_set_cookie();
  127. }
  128. // Do the tokens exist in both the _POST and _COOKIE arrays?
  129. if ( ! isset($_POST[$this->_csrf_token_name]) OR
  130. ! isset($_COOKIE[$this->_csrf_cookie_name]))
  131. {
  132. $this->csrf_show_error();
  133. }
  134. // Do the tokens match?
  135. if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
  136. {
  137. $this->csrf_show_error();
  138. }
  139. // We kill this since we're done and we don't want to
  140. // polute the _POST array
  141. unset($_POST[$this->_csrf_token_name]);
  142. // Nothing should last forever
  143. unset($_COOKIE[$this->_csrf_cookie_name]);
  144. $this->_csrf_set_hash();
  145. $this->csrf_set_cookie();
  146. log_message('debug', "CSRF token verified ");
  147. return $this;
  148. }
  149. // --------------------------------------------------------------------
  150. /**
  151. * Set Cross Site Request Forgery Protection Cookie
  152. *
  153. * @return object
  154. */
  155. public function csrf_set_cookie()
  156. {
  157. $expire = time() + $this->_csrf_expire;
  158. $secure_cookie = (config_item('cookie_secure') === TRUE) ? 1 : 0;
  159. if ($secure_cookie)
  160. {
  161. $req = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : FALSE;
  162. if ( ! $req OR $req == 'off')
  163. {
  164. return FALSE;
  165. }
  166. }
  167. setcookie($this->_csrf_cookie_name, $this->_csrf_hash, $expire, config_item('cookie_path'), config_item('cookie_domain'), $secure_cookie);
  168. log_message('debug', "CRSF cookie Set");
  169. return $this;
  170. }
  171. // --------------------------------------------------------------------
  172. /**
  173. * Show CSRF Error
  174. *
  175. * @return void
  176. */
  177. public function csrf_show_error()
  178. {
  179. show_error('The action you have requested is not allowed.');
  180. }
  181. // --------------------------------------------------------------------
  182. /**
  183. * Get CSRF Hash
  184. *
  185. * Getter Method
  186. *
  187. * @return string self::_csrf_hash
  188. */
  189. public function get_csrf_hash()
  190. {
  191. return $this->_csrf_hash;
  192. }
  193. // --------------------------------------------------------------------
  194. /**
  195. * Get CSRF Token Name
  196. *
  197. * Getter Method
  198. *
  199. * @return string self::csrf_token_name
  200. */
  201. public function get_csrf_token_name()
  202. {
  203. return $this->_csrf_token_name;
  204. }
  205. // --------------------------------------------------------------------
  206. /**
  207. * XSS Clean
  208. *
  209. * Sanitizes data so that Cross Site Scripting Hacks can be
  210. * prevented. This function does a fair amount of work but
  211. * it is extremely thorough, designed to prevent even the
  212. * most obscure XSS attempts. Nothing is ever 100% foolproof,
  213. * of course, but I haven't been able to get anything passed
  214. * the filter.
  215. *
  216. * Note: This function should only be used to deal with data
  217. * upon submission. It's not something that should
  218. * be used for general runtime processing.
  219. *
  220. * This function was based in part on some code and ideas I
  221. * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention
  222. *
  223. * To help develop this script I used this great list of
  224. * vulnerabilities along with a few other hacks I've
  225. * harvested from examining vulnerabilities in other programs:
  226. * http://ha.ckers.org/xss.html
  227. *
  228. * @param mixed string or array
  229. * @param bool
  230. * @return string
  231. */
  232. public function xss_clean($str, $is_image = FALSE)
  233. {
  234. /*
  235. * Is the string an array?
  236. *
  237. */
  238. if (is_array($str))
  239. {
  240. while (list($key) = each($str))
  241. {
  242. $str[$key] = $this->xss_clean($str[$key]);
  243. }
  244. return $str;
  245. }
  246. /*
  247. * Remove Invisible Characters
  248. */
  249. $str = remove_invisible_characters($str);
  250. // Validate Entities in URLs
  251. $str = $this->_validate_entities($str);
  252. /*
  253. * URL Decode
  254. *
  255. * Just in case stuff like this is submitted:
  256. *
  257. * <a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
  258. *
  259. * Note: Use rawurldecode() so it does not remove plus signs
  260. *
  261. */
  262. $str = rawurldecode($str);
  263. /*
  264. * Convert character entities to ASCII
  265. *
  266. * This permits our tests below to work reliably.
  267. * We only convert entities that are within tags since
  268. * these are the ones that will pose security problems.
  269. *
  270. */
  271. $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
  272. $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_decode_entity'), $str);
  273. /*
  274. * Remove Invisible Characters Again!
  275. */
  276. $str = remove_invisible_characters($str);
  277. /*
  278. * Convert all tabs to spaces
  279. *
  280. * This prevents strings like this: ja vascript
  281. * NOTE: we deal with spaces between characters later.
  282. * NOTE: preg_replace was found to be amazingly slow here on
  283. * large blocks of data, so we use str_replace.
  284. */
  285. if (strpos($str, "\t") !== FALSE)
  286. {
  287. $str = str_replace("\t", ' ', $str);
  288. }
  289. /*
  290. * Capture converted string for later comparison
  291. */
  292. $converted_string = $str;
  293. // Remove Strings that are never allowed
  294. $str = $this->_do_never_allowed($str);
  295. /*
  296. * Makes PHP tags safe
  297. *
  298. * Note: XML tags are inadvertently replaced too:
  299. *
  300. * <?xml
  301. *
  302. * But it doesn't seem to pose a problem.
  303. */
  304. if ($is_image === TRUE)
  305. {
  306. // Images have a tendency to have the PHP short opening and
  307. // closing tags every so often so we skip those and only
  308. // do the long opening tags.
  309. $str = preg_replace('/<\?(php)/i', "&lt;?\\1", $str);
  310. }
  311. else
  312. {
  313. $str = str_replace(array('<?', '?'.'>'), array('&lt;?', '?&gt;'), $str);
  314. }
  315. /*
  316. * Compact any exploded words
  317. *
  318. * This corrects words like: j a v a s c r i p t
  319. * These words are compacted back to their correct state.
  320. */
  321. $words = array(
  322. 'javascript', 'expression', 'vbscript', 'script',
  323. 'applet', 'alert', 'document', 'write', 'cookie', 'window'
  324. );
  325. foreach ($words as $word)
  326. {
  327. $temp = '';
  328. for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
  329. {
  330. $temp .= substr($word, $i, 1)."\s*";
  331. }
  332. // We only want to do this when it is followed by a non-word character
  333. // That way valid stuff like "dealer to" does not become "dealerto"
  334. $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
  335. }
  336. /*
  337. * Remove disallowed Javascript in links or img tags
  338. * We used to do some version comparisons and use of stripos for PHP5,
  339. * but it is dog slow compared to these simplified non-capturing
  340. * preg_match(), especially if the pattern exists in the string
  341. */
  342. do
  343. {
  344. $original = $str;
  345. if (preg_match("/<a/i", $str))
  346. {
  347. $str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
  348. }
  349. if (preg_match("/<img/i", $str))
  350. {
  351. $str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);
  352. }
  353. if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
  354. {
  355. $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
  356. }
  357. }
  358. while($original != $str);
  359. unset($original);
  360. // Remove evil attributes such as style, onclick and xmlns
  361. $str = $this->_remove_evil_attributes($str, $is_image);
  362. /*
  363. * Sanitize naughty HTML elements
  364. *
  365. * If a tag containing any of the words in the list
  366. * below is found, the tag gets converted to entities.
  367. *
  368. * So this: <blink>
  369. * Becomes: &lt;blink&gt;
  370. */
  371. $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
  372. $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);
  373. /*
  374. * Sanitize naughty scripting elements
  375. *
  376. * Similar to above, only instead of looking for
  377. * tags it looks for PHP and JavaScript commands
  378. * that are disallowed. Rather than removing the
  379. * code, it simply converts the parenthesis to entities
  380. * rendering the code un-executable.
  381. *
  382. * For example: eval('some code')
  383. * Becomes: eval&#40;'some code'&#41;
  384. */
  385. $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);
  386. // Final clean up
  387. // This adds a bit of extra precaution in case
  388. // something got through the above filters
  389. $str = $this->_do_never_allowed($str);
  390. /*
  391. * Images are Handled in a Special Way
  392. * - Essentially, we want to know that after all of the character
  393. * conversion is done whether any unwanted, likely XSS, code was found.
  394. * If not, we return TRUE, as the image is clean.
  395. * However, if the string post-conversion does not matched the
  396. * string post-removal of XSS, then it fails, as there was unwanted XSS
  397. * code found and removed/changed during processing.
  398. */
  399. if ($is_image === TRUE)
  400. {
  401. return ($str == $converted_string) ? TRUE: FALSE;
  402. }
  403. log_message('debug', "XSS Filtering completed");
  404. return $str;
  405. }
  406. // --------------------------------------------------------------------
  407. /**
  408. * Random Hash for protecting URLs
  409. *
  410. * @return string
  411. */
  412. public function xss_hash()
  413. {
  414. if ($this->_xss_hash == '')
  415. {
  416. mt_srand();
  417. $this->_xss_hash = md5(time() + mt_rand(0, 1999999999));
  418. }
  419. return $this->_xss_hash;
  420. }
  421. // --------------------------------------------------------------------
  422. /**
  423. * HTML Entities Decode
  424. *
  425. * This function is a replacement for html_entity_decode()
  426. *
  427. * The reason we are not using html_entity_decode() by itself is because
  428. * while it is not technically correct to leave out the semicolon
  429. * at the end of an entity most browsers will still interpret the entity
  430. * correctly. html_entity_decode() does not convert entities without
  431. * semicolons, so we are left with our own little solution here. Bummer.
  432. *
  433. * @param string
  434. * @param string
  435. * @return string
  436. */
  437. public function entity_decode($str, $charset='UTF-8')
  438. {
  439. if (stristr($str, '&') === FALSE)
  440. {
  441. return $str;
  442. }
  443. $str = html_entity_decode($str, ENT_COMPAT, $charset);
  444. $str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
  445. return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
  446. }
  447. // --------------------------------------------------------------------
  448. /**
  449. * Filename Security
  450. *
  451. * @param string
  452. * @param bool
  453. * @return string
  454. */
  455. public function sanitize_filename($str, $relative_path = FALSE)
  456. {
  457. $bad = array(
  458. "../",
  459. "<!--",
  460. "-->",
  461. "<",
  462. ">",
  463. "'",
  464. '"',
  465. '&',
  466. '$',
  467. '#',
  468. '{',
  469. '}',
  470. '[',
  471. ']',
  472. '=',
  473. ';',
  474. '?',
  475. "%20",
  476. "%22",
  477. "%3c", // <
  478. "%253c", // <
  479. "%3e", // >
  480. "%0e", // >
  481. "%28", // (
  482. "%29", // )
  483. "%2528", // (
  484. "%26", // &
  485. "%24", // $
  486. "%3f", // ?
  487. "%3b", // ;
  488. "%3d" // =
  489. );
  490. if ( ! $relative_path)
  491. {
  492. $bad[] = './';
  493. $bad[] = '/';
  494. }
  495. $str = remove_invisible_characters($str, FALSE);
  496. return stripslashes(str_replace($bad, '', $str));
  497. }
  498. // ----------------------------------------------------------------
  499. /**
  500. * Compact Exploded Words
  501. *
  502. * Callback function for xss_clean() to remove whitespace from
  503. * things like j a v a s c r i p t
  504. *
  505. * @param type
  506. * @return type
  507. */
  508. protected function _compact_exploded_words($matches)
  509. {
  510. return preg_replace('/\s+/s', '', $matches[1]).$matches[2];
  511. }
  512. // --------------------------------------------------------------------
  513. /*
  514. * Remove Evil HTML Attributes (like evenhandlers and style)
  515. *
  516. * It removes the evil attribute and either:
  517. * - Everything up until a space
  518. * For example, everything between the pipes:
  519. * <a |style=document.write('hello');alert('world');| class=link>
  520. * - Everything inside the quotes
  521. * For example, everything between the pipes:
  522. * <a |style="document.write('hello'); alert('world');"| class="link">
  523. *
  524. * @param string $str The string to check
  525. * @param boolean $is_image TRUE if this is an image
  526. * @return string The string with the evil attributes removed
  527. */
  528. protected function _remove_evil_attributes($str, $is_image)
  529. {
  530. // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns
  531. $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction');
  532. if ($is_image === TRUE)
  533. {
  534. /*
  535. * Adobe Photoshop puts XML metadata into JFIF images,
  536. * including namespacing, so we have to allow this for images.
  537. */
  538. unset($evil_attributes[array_search('xmlns', $evil_attributes)]);
  539. }
  540. do {
  541. $count = 0;
  542. $attribs = array();
  543. // find occurrences of illegal attribute strings without quotes
  544. preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*([^\s]*)/is", $str, $matches, PREG_SET_ORDER);
  545. foreach ($matches as $attr)
  546. {
  547. $attribs[] = preg_quote($attr[0], '/');
  548. }
  549. // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
  550. preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is", $str, $matches, PREG_SET_ORDER);
  551. foreach ($matches as $attr)
  552. {
  553. $attribs[] = preg_quote($attr[0], '/');
  554. }
  555. // replace illegal attribute strings that are inside an html tag
  556. if (count($attribs) > 0)
  557. {
  558. $str = preg_replace("/<(\/?[^><]+?)([^A-Za-z\-])(".implode('|', $attribs).")([\s><])([><]*)/i", '<$1$2$4$5', $str, -1, $count);
  559. }
  560. } while ($count);
  561. return $str;
  562. }
  563. // --------------------------------------------------------------------
  564. /**
  565. * Sanitize Naughty HTML
  566. *
  567. * Callback function for xss_clean() to remove naughty HTML elements
  568. *
  569. * @param array
  570. * @return string
  571. */
  572. protected function _sanitize_naughty_html($matches)
  573. {
  574. // encode opening brace
  575. $str = '&lt;'.$matches[1].$matches[2].$matches[3];
  576. // encode captured opening or closing brace to prevent recursive vectors
  577. $str .= str_replace(array('>', '<'), array('&gt;', '&lt;'),
  578. $matches[4]);
  579. return $str;
  580. }
  581. // --------------------------------------------------------------------
  582. /**
  583. * JS Link Removal
  584. *
  585. * Callback function for xss_clean() to sanitize links
  586. * This limits the PCRE backtracks, making it more performance friendly
  587. * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
  588. * PHP 5.2+ on link-heavy strings
  589. *
  590. * @param array
  591. * @return string
  592. */
  593. protected function _js_link_removal($match)
  594. {
  595. $attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
  596. return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
  597. }
  598. // --------------------------------------------------------------------
  599. /**
  600. * JS Image Removal
  601. *
  602. * Callback function for xss_clean() to sanitize image tags
  603. * This limits the PCRE backtracks, making it more performance friendly
  604. * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
  605. * PHP 5.2+ on image tag heavy strings
  606. *
  607. * @param array
  608. * @return string
  609. */
  610. protected function _js_img_removal($match)
  611. {
  612. $attributes = $this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]));
  613. return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
  614. }
  615. // --------------------------------------------------------------------
  616. /**
  617. * Attribute Conversion
  618. *
  619. * Used as a callback for XSS Clean
  620. *
  621. * @param array
  622. * @return string
  623. */
  624. protected function _convert_attribute($match)
  625. {
  626. return str_replace(array('>', '<', '\\'), array('&gt;', '&lt;', '\\\\'), $match[0]);
  627. }
  628. // --------------------------------------------------------------------
  629. /**
  630. * Filter Attributes
  631. *
  632. * Filters tag attributes for consistency and safety
  633. *
  634. * @param string
  635. * @return string
  636. */
  637. protected function _filter_attributes($str)
  638. {
  639. $out = '';
  640. if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
  641. {
  642. foreach ($matches[0] as $match)
  643. {
  644. $out .= preg_replace("#/\*.*?\*/#s", '', $match);
  645. }
  646. }
  647. return $out;
  648. }
  649. // --------------------------------------------------------------------
  650. /**
  651. * HTML Entity Decode Callback
  652. *
  653. * Used as a callback for XSS Clean
  654. *
  655. * @param array
  656. * @return string
  657. */
  658. protected function _decode_entity($match)
  659. {
  660. return $this->entity_decode($match[0], strtoupper(config_item('charset')));
  661. }
  662. // --------------------------------------------------------------------
  663. /**
  664. * Validate URL entities
  665. *
  666. * Called by xss_clean()
  667. *
  668. * @param string
  669. * @return string
  670. */
  671. protected function _validate_entities($str)
  672. {
  673. /*
  674. * Protect GET variables in URLs
  675. */
  676. // 901119URL5918AMP18930PROTECT8198
  677. $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash()."\\1=\\2", $str);
  678. /*
  679. * Validate standard character entities
  680. *
  681. * Add a semicolon if missing. We do this to enable
  682. * the conversion of entities to ASCII later.
  683. *
  684. */
  685. $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str);
  686. /*
  687. * Validate UTF16 two byte encoding (x00)
  688. *
  689. * Just as above, adds a semicolon if missing.
  690. *
  691. */
  692. $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);
  693. /*
  694. * Un-Protect GET variables in URLs
  695. */
  696. $str = str_replace($this->xss_hash(), '&', $str);
  697. return $str;
  698. }
  699. // ----------------------------------------------------------------------
  700. /**
  701. * Do Never Allowed
  702. *
  703. * A utility function for xss_clean()
  704. *
  705. * @param string
  706. * @return string
  707. */
  708. protected function _do_never_allowed($str)
  709. {
  710. foreach ($this->_never_allowed_str as $key => $val)
  711. {
  712. $str = str_replace($key, $val, $str);
  713. }
  714. foreach ($this->_never_allowed_regex as $key => $val)
  715. {
  716. $str = preg_replace("#".$key."#i", $val, $str);
  717. }
  718. return $str;
  719. }
  720. // --------------------------------------------------------------------
  721. /**
  722. * Set Cross Site Request Forgery Protection Cookie
  723. *
  724. * @return string
  725. */
  726. protected function _csrf_set_hash()
  727. {
  728. if ($this->_csrf_hash == '')
  729. {
  730. // If the cookie exists we will use it's value.
  731. // We don't necessarily want to regenerate it with
  732. // each page load since a page could contain embedded
  733. // sub-pages causing this feature to fail
  734. if (isset($_COOKIE[$this->_csrf_cookie_name]) &&
  735. $_COOKIE[$this->_csrf_cookie_name] != '')
  736. {
  737. return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
  738. }
  739. return $this->_csrf_hash = md5(uniqid(rand(), TRUE));
  740. }
  741. return $this->_csrf_hash;
  742. }
  743. }
  744. // END Security Class
  745. /* End of file Security.php */
  746. /* Location: ./system/libraries/Security.php */