PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/system/codeigniter/system/core/Security.php

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