Security.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * Security helper class.
  4. *
  5. * @package Kohana
  6. * @category Security
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. class Kohana_Security {
  12. /**
  13. * @var string key name used for token storage
  14. */
  15. public static $token_name = 'security_token';
  16. /**
  17. * Generate and store a unique token which can be used to help prevent
  18. * [CSRF](http://wikipedia.org/wiki/Cross_Site_Request_Forgery) attacks.
  19. *
  20. * $token = Security::token();
  21. *
  22. * You can insert this token into your forms as a hidden field:
  23. *
  24. * echo Form::hidden('csrf', Security::token());
  25. *
  26. * And then check it when using [Validation]:
  27. *
  28. * $array->rules('csrf', array(
  29. * array('not_empty'),
  30. * array('Security::check'),
  31. * ));
  32. *
  33. * This provides a basic, but effective, method of preventing CSRF attacks.
  34. *
  35. * @param boolean $new force a new token to be generated?
  36. * @return string
  37. * @uses Session::instance
  38. */
  39. public static function token($new = FALSE)
  40. {
  41. $session = Session::instance();
  42. // Get the current token
  43. $token = $session->get(Security::$token_name);
  44. if ($new === TRUE OR ! $token)
  45. {
  46. $token = Security::_generate_token();
  47. // Store the new token
  48. $session->set(Security::$token_name, $token);
  49. }
  50. return $token;
  51. }
  52. /**
  53. * Generate a unique token.
  54. *
  55. * @return string
  56. */
  57. protected static function _generate_token()
  58. {
  59. if (function_exists('random_bytes'))
  60. {
  61. try
  62. {
  63. return bin2hex(random_bytes(24));
  64. }
  65. catch (Exception $e)
  66. {
  67. // Random bytes function is available but no sources of randomness are available
  68. // so rather than allowing the exception to be thrown - fall back to other methods.
  69. // @see http://php.net/manual/en/function.random-bytes.php
  70. }
  71. }
  72. if (function_exists('openssl_random_pseudo_bytes'))
  73. {
  74. // Generate a random pseudo bytes token if openssl_random_pseudo_bytes is available
  75. // This is more secure than uniqid, because uniqid relies on microtime, which is predictable
  76. return base64_encode(openssl_random_pseudo_bytes(32));
  77. }
  78. else
  79. {
  80. // Otherwise, fall back to a hashed uniqid
  81. return sha1(uniqid(NULL, TRUE));
  82. }
  83. }
  84. /**
  85. * Check that the given token matches the currently stored security token.
  86. *
  87. * if (Security::check($token))
  88. * {
  89. * // Pass
  90. * }
  91. *
  92. * @param string $token token to check
  93. * @return boolean
  94. * @uses Security::token
  95. */
  96. public static function check($token)
  97. {
  98. return Security::slow_equals(Security::token(), $token);
  99. }
  100. /**
  101. * Compare two hashes in a time-invariant manner.
  102. * Prevents cryptographic side-channel attacks (timing attacks, specifically)
  103. *
  104. * @param string $a cryptographic hash
  105. * @param string $b cryptographic hash
  106. * @return boolean
  107. */
  108. public static function slow_equals($a, $b)
  109. {
  110. $diff = strlen($a) ^ strlen($b);
  111. for($i = 0; $i < strlen($a) AND $i < strlen($b); $i++)
  112. {
  113. $diff |= ord($a[$i]) ^ ord($b[$i]);
  114. }
  115. return $diff === 0;
  116. }
  117. /**
  118. * Deprecated for security reasons.
  119. * See https://github.com/kohana/kohana/issues/107
  120. *
  121. * Remove image tags from a string.
  122. *
  123. * $str = Security::strip_image_tags($str);
  124. *
  125. * @deprecated since version 3.3.6
  126. * @param string $str string to sanitize
  127. * @return string
  128. */
  129. public static function strip_image_tags($str)
  130. {
  131. return preg_replace('#<img\s.*?(?:src\s*=\s*["\']?([^"\'<>\s]*)["\']?[^>]*)?>#is', '$1', $str);
  132. }
  133. /**
  134. * Encodes PHP tags in a string.
  135. *
  136. * $str = Security::encode_php_tags($str);
  137. *
  138. * @param string $str string to sanitize
  139. * @return string
  140. */
  141. public static function encode_php_tags($str)
  142. {
  143. return str_replace(['<?', '?>'], ['&lt;?', '?&gt;'], $str);
  144. }
  145. }