PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/system/core/Security.php

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