当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > PHP的SESSIONID生成的原理

PHP的SESSIONID生成的原理 时间:2018-09-28      来源:未知

PHP的SESSIONID生成的原理

作为一个web程序猿,我们对session肯定都不陌生,session id是我们各自在服务器上的一个唯一标志,这个id串既可以由php自动来生成,也可以由我们来赋予。你们可能和我一样,很关心php自动生成的那个id串是怎么来的,冲突的概率有多大,以及容不容易被别人计算出来,所以有了下文。

 

我们写一下php5.3.6的源码,进入/ext/session目录,生成session id的函数位于session.c文件的345行,下面详细介绍一下这个函数。

1. PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */

2. {

3.

4. //这几行行定义了些散列函数所需的数据,直接越过~

5. PHP_MD5_CTX md5_context;

6. PHP_SHA1_CTX sha1_context;

7.

8. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)

9. void *hash_context;

10. #endif

11.

12. unsigned char *digest;

13. int digest_len;

14. int j;

15.

16. char *buf, *outid;

17.

18. zval **array;

19. zval **token;

20.

21. //用来记录$_SERVER['REMOTE_ADDR']的值

22. char *remote_addr = NULL;

23.

24. //一个timeval结构,用来记录当前的时间戳及毫秒数

25. struct timeval tv;

26. gettimeofday(&tv, NULL);

27.

28. //如果可能的话,就对remote_ADDR进行赋值,用php伪代码表示便是:

29. //if(isset($_SERVER['REMOTE_ADDR']))

30. //{remote_addr = $_SERVER['REMOTE_ADDR'];}

31. //备注:在cli模式下是没有的~

32. if (

33.      zend_hash_find(

34.          &EG(symbol_table),

35.          "_SERVER",

36.          sizeof("_SERVER"),

37.          (void **) &array

38.      ) == SUCCESS

39.      && Z_TYPE_PP(array) == IS_ARRAY

40.      && zend_hash_find(

41.          Z_ARRVAL_PP(array),

42.          "REMOTE_ADDR",

43.          sizeof("REMOTE_ADDR"),

44.          (void **) &token

45.      ) == SUCCESS

46. )

47. {

48.      remote_addr = Z_STRVAL_PP(token);

49. }

50.

51. /* maximum 15+19+19+10 bytes */

52. //生成所需的session id,当然后面还需要后续的处理~

53. //格式为:%.15s%ld%ld%0.8F,每一段的含义如下:

54. //%.15s    remote_addr ? remote_addr : "" 这一行很容易理解

55. //%ld        tv.tv_sec    当前的时间戳

56. //%ld        (long int)tv.tv_usec 当前毫秒数

57. //%0.8F    php_combined_lcg(TSRMLS_C) * 10 一个随机数

58. spprintf(

59.      &buf,

60.      0,

61.      "%.15s%ld%ld%0.8F",

62.      remote_addr ? remote_addr : "",

63.      tv.tv_sec,

64.      (long int)tv.tv_usec,

65.      php_combined_lcg(TSRMLS_C) * 10

66. );

67.

68. //下面对buf字符串的值进行散列处理

69. //检测session配置中的散列函数

70. /*

71. 300行:    enum{

72.             PS_HASH_FUNC_MD5,

73.             PS_HASH_FUNC_SHA1,

74.             PS_HASH_FUNC_OTHER

75.         };

76. 812行:

77. PHP_INI_ENTRY("session.hash_function","0",PHP_INI_ALL,OnUpdateHashFunc)

78. 738行:

79. static PHP_INI_MH(OnUpdateHashFunc)

80. {

81.     ......

82.     ......

83.     val = strtol(new_value, &endptr, 10);

84.     if (endptr && (*endptr == '\0'))

85.     {

86.         /* Numeric value */

87.          PS(hash_func) = val ? 1 : 0;

88.          return SUCCESS;

89.      }

90.      ......

91.      ......

92. 可知PS(hash_func)的默认值为0,即PS_HASH_FUNC_MD5。

93. */

94.

95. switch (PS(hash_func))

96. {

97.      //如果是md5,则用md5算法对我们的buf串进行散列处理。

98.      case PS_HASH_FUNC_MD5:

99.          PHP_MD5Init(&md5_context);

100.          PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));

101.          digest_len = 16;

102.          break;

103.

104.      //如果是SHA1,则用SHA1算法对我们的buf串进行散列处理。

105.      case PS_HASH_FUNC_SHA1:

106.          PHP_SHA1Init(&sha1_context);

107.          PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf));

108.          digest_len = 20;

109.          break;

110.

111. #if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)

112.      case PS_HASH_FUNC_OTHER:

113.          if (!PS(hash_ops))

114.          {

115.              php_error_docref(

116.                  NULL TSRMLS_CC,

117.                  E_ERROR,

118.                  "Invalid session hash function"

119.              );

120.              efree(buf);

121.              return NULL;

122.          }

123.

124.          hash_context = emalloc(PS(hash_ops)->context_size);

125.          PS(hash_ops)->hash_init(hash_context);

126.          PS(hash_ops)->hash_update(hash_context, (unsigned char *) buf, strlen(buf));

127.          digest_len = PS(hash_ops)->digest_size;

128.          break;

129. #endif /* HAVE_HASH_EXT */

130.

131.      //如果没有散列函数,则报错,还是E_ERROR级别的

132.      default:

133.          php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");

134.          efree(buf);

135.          return NULL;

136. }

137.

138. //释放buf~

139. //内容已经去我们的hash_context里,比如md5_context、sha1_context。。。。。。

140. efree(buf);

141.

142. /*

143. session.entropy_file 给出了一个到外部资源(文件)的路径,

144. 该资源将在会话 ID 创建进程中被用作附加的熵值资源。

145. 例如在许多 Unix 系统下都可以用 /dev/random 或 /dev/urandom。

146. session.entropy_length 指定了从上面的文件中读取的字节数。默认为 0(禁用)。

147.

148. 如果entropy_length这个配置大于0,则:

149. */

150. if (PS(entropy_length) > 0)

151. {

152. #ifdef PHP_WIN32

153.      unsigned char rbuf[2048];

154.      size_t toread = PS(entropy_length);

155.      if (php_win32_get_random_bytes(rbuf, (size_t) toread) == SUCCESS)

156.      {

157.          switch (PS(hash_func))

158.          {

159.              case PS_HASH_FUNC_MD5:

160.                  PHP_MD5Update(&md5_context, rbuf, toread);

161.                  break;

162.              case PS_HASH_FUNC_SHA1:

163.                  PHP_SHA1Update(&sha1_context, rbuf, toread);

164.                  break;

165. # if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)

166.              case PS_HASH_FUNC_OTHER:

167.                  PS(hash_ops)->hash_update(hash_context, rbuf, toread);

168.                  break;

169. # endif /* HAVE_HASH_EXT */

170.          }

171.      }

172. #else

173.      int fd;

174.      fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);

175.      if (fd >= 0)

176.      {

177.          unsigned char rbuf[2048];

178.          int n;

179.          int to_read = PS(entropy_length);

180.          while (to_read > 0) {

181.              n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));

182.              if (n hash_update(hash_context, rbuf, n);

183.                      break;

184. #endif /* HAVE_HASH_EXT */

185.              }

186.              to_read -= n;

187.          }

188.          close(fd);

189.      }

190. //结束entropy_length>0时的逻辑

191. #endif

192. }

193.

194. //还是散列计算的一部分,看来我们的hash_final(digest, hash_context);

195.          efree(hash_context);

196.          break;

197. #endif /* HAVE_HASH_EXT */

198. }

199.

200. /*

201. session.hash_bits_per_character允许用户定义将二进制散列数据转换为可读的格式时每个字符存放多少个比特。

202. 可能值为 '4'(0-9,a-f),'5'(0-9,a-v),以及 '6'(0-9,a-z,A-Z,"-",",")。

203. */

204. if (PS(hash_bits_per_character) < 4

205.          || PS(hash_bits_per_character) > 6) {

206.      PS(hash_bits_per_character) = 4;

207.      php_error_docref(

208.          NULL TSRMLS_CC,

209.          E_WARNING,

210.          "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now"

211.      );

212. }

213.

214. //将散列后的二进制数据digest用字符串表示成可读的形式,并放置在outid字符串里

215. outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5)));

216. j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid);

217. efree(digest);

218. if (newlen) {

219.      *newlen = j;

220. }

221.

222. //返回outid

223. return outid;

224. }

根据以上代码可以得出结论,PHP的默认session_id生成算法还是比较随机的,除非攻击者能够同时猜中时间戳、毫秒数、后面的那个随机数。否则,安全系数还是很高的。

上一篇:JavaScript 错误处理和堆栈追踪浅析

下一篇:基于物联网项目的共享内存

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部