Secure.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php namespace Dever\Helper;
  2. use Dever;
  3. class Secure
  4. {
  5. private static $token = false;
  6. public static function login($uid, $extend = false)
  7. {
  8. $auth = '';
  9. $data = Dever::json_encode(array($uid, time(), $extend));
  10. return self::encode($data);
  11. }
  12. public static function checkLogin($signature, $time = 604800)
  13. {
  14. self::repeat($signature, $time);
  15. $auth = Dever::json_decode(self::decode($signature));
  16. if (isset($auth[0]) && isset($auth[1]) && $auth[0] && $auth[0] > 0) {
  17. if (time() - $auth[1] < $time) {
  18. return array('uid' => $auth[0], 'time' => $auth[1], 'extend' => $auth[2]);
  19. }
  20. }
  21. return false;
  22. }
  23. public static function get($request, $token = false)
  24. {
  25. if ($token) {
  26. self::$token = $token;
  27. }
  28. $time = self::timestamp();
  29. $nonce = self::nonce();
  30. $signature = self::signature($time, $nonce, $request);
  31. $request += array (
  32. 'time' => $time,
  33. 'nonce' => $nonce,
  34. 'signature' => $signature,
  35. );
  36. return $request;
  37. }
  38. public static function check($request = array(), $time = 300, $token = false)
  39. {
  40. if ($token) {
  41. self::$token = $token;
  42. }
  43. if (!$request) {
  44. $request = Dever::input();
  45. }
  46. if (empty($request['signature']) || empty($request['nonce'])) {
  47. Dever::error('signature不存在');
  48. }
  49. if (isset($request['l'])) {
  50. unset($request['l']);
  51. }
  52. if (isset($request['shell'])) {
  53. unset($request['shell']);
  54. }
  55. if (empty($request['time'])) {
  56. return self::checkLogin($request['signature']);
  57. }
  58. self::repeat($request['signature'], $time);
  59. if (time() - $request['time'] > $time) {
  60. Dever::error('signature已过期');
  61. }
  62. $signature = self::signature($request['time'], $request['nonce'], $request);
  63. if ($request['signature'] != $signature) {
  64. Dever::error('signature验签失败');
  65. }
  66. return $signature;
  67. }
  68. public static function signature($time, $nonce, $request = array())
  69. {
  70. if (isset($request['signature'])) {
  71. unset($request['signature']);
  72. }
  73. $request['token'] = self::token();
  74. $request['time'] = $time;
  75. $request['nonce'] = $nonce;
  76. ksort($request);
  77. $signature_string = '';
  78. foreach ($request as $k => $v) {
  79. if (is_array($v)) {
  80. continue;
  81. }
  82. $signature_string .= $k . '=' . $v . '&';
  83. }
  84. $signature_string = rtrim($signature_string, '&');
  85. return md5($signature_string);
  86. }
  87. public static function token()
  88. {
  89. if (self::$token) {
  90. return self::$token;
  91. }
  92. return Dever::config('setting')['token'];
  93. }
  94. public static function nonce()
  95. {
  96. return substr(sha1(microtime()), rand(10, 15));
  97. }
  98. public static function timestamp()
  99. {
  100. return Date::mtime();
  101. }
  102. public static function repeat($value, $expire)
  103. {
  104. return;
  105. if (isset(Dever::config('setting')['redis']) && !Redis::lock($value, 1, $expire)) {
  106. Dever::error('signature不能重复使用');
  107. }
  108. }
  109. public static function encode($string, $key = '')
  110. {
  111. $ckey_length = 5;
  112. if (!$key) {
  113. $key = self::token();
  114. }
  115. $key = sha1($key);
  116. $keya = md5(substr($key, 0, 16));
  117. $keyb = md5(substr($key, 16, 16));
  118. $keyc = ''; //md5串后4位,每次不一样
  119. if ($ckey_length) {
  120. $keyc = substr(md5(microtime()), -$ckey_length);
  121. }
  122. $cryptkey = $keya . md5($keya . $keyc); //两个md5串
  123. $key_length = strlen($cryptkey); //64
  124. $string = sprintf('%010d', time()) . substr(md5($string . $keyb), 0, 16) . $string;
  125. $string_length = strlen($string);
  126. $result = '';
  127. $box = range(0, 255);
  128. $rndkey = array();
  129. for ($i = 0; $i <= 255; $i++) {
  130. $rndkey[$i] = ord($cryptkey[$i % $key_length]); //生成一个255个元素的数组
  131. }
  132. for ($j = $i = 0; $i < 256; $i++) {
  133. //将$box数组转换为无序并且个数不变的数据
  134. $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  135. $tmp = $box[$i];
  136. $box[$i] = $box[$j];
  137. $box[$j] = $tmp;
  138. }
  139. for ($a = $j = $i = 0; $i < $string_length; $i++) {
  140. $a = ($a + 1) % 256;
  141. $j = ($j + $box[$a]) % 256;
  142. $tmp = $box[$a];
  143. $box[$a] = $box[$j];
  144. $box[$j] = $tmp;
  145. $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  146. }
  147. return $keyc . str_replace('=', '', self::base64_encode($result));
  148. }
  149. public static function decode($string, $key = "")
  150. {
  151. $ckey_length = 5;
  152. if (!$key) {
  153. $key = self::token();
  154. }
  155. $key = sha1($key);
  156. $keya = md5(substr($key, 0, 16));
  157. $keyb = md5(substr($key, 16, 16));
  158. $keyc = '';//和encrypt时的$keyc一样
  159. if ($ckey_length) {
  160. $keyc = substr($string, 0, $ckey_length);
  161. }
  162. $cryptkey = $keya . md5($keya . $keyc);
  163. $key_length = strlen($cryptkey);
  164. $string = self::base64_decode(substr($string, $ckey_length));
  165. $string_length = strlen($string);
  166. $result = '';
  167. $box = range(0, 255);
  168. $rndkey = array();
  169. for ($i = 0; $i <= 255; $i++) {
  170. $rndkey[$i] = ord($cryptkey[$i % $key_length]);
  171. }
  172. for ($j = $i = 0; $i < 256; $i++) {
  173. //和encrypt时的$box一样
  174. $j = ($j + $box[$i] + $rndkey[$i]) % 256;
  175. $tmp = $box[$i];
  176. $box[$i] = $box[$j];
  177. $box[$j] = $tmp;
  178. }
  179. for ($a = $j = $i = 0; $i < $string_length; $i++) {
  180. //核心操作,解密
  181. $a = ($a + 1) % 256;
  182. $j = ($j + $box[$a]) % 256;
  183. $tmp = $box[$a];
  184. $box[$a] = $box[$j];
  185. $box[$j] = $tmp;
  186. $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
  187. }
  188. if (substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
  189. return substr($result, 26);
  190. } else {
  191. return '';
  192. }
  193. }
  194. public static function base64_encode($string)
  195. {
  196. if (!$string) {
  197. return false;
  198. }
  199. $encodestr = base64_encode($string);
  200. $encodestr = str_replace(array('+', '/'), array('-', '_'), $encodestr);
  201. return $encodestr;
  202. }
  203. public static function base64_decode($string)
  204. {
  205. if (!$string) {
  206. return false;
  207. }
  208. $string = str_replace(array('-', '_'), array('+', '/'), $string);
  209. $decodestr = base64_decode($string);
  210. return $decodestr;
  211. }
  212. public static function xss($data)
  213. {
  214. if (!is_string($data)) {
  215. return $data;
  216. }
  217. $data = htmlspecialchars_decode($data);
  218. $data = str_replace(array('&amp;', '&lt;', '&gt;'), array('&amp;amp;', '&amp;lt;', '&amp;gt;'), $data);
  219. $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
  220. $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
  221. $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
  222. $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
  223. $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
  224. $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
  225. $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
  226. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
  227. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
  228. $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
  229. $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
  230. do {
  231. $old_data = $data;
  232. $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
  233. } while ($old_data !== $data);
  234. return $data;
  235. }
  236. }