PHPのデフォルトのセッションを解析id生成アルゴリズム
6394 ワード
Webプログラムの猿として、私たちはsessionに対してきっとよく知らないに違いありません.session idは私たちがそれぞれサーバー上の唯一の標識で、このid列はphpで自動的に生成することができて、私たちが与えることができます.あなたたちは私と同じように、phpが自動的に生成したid列がどのように来たのか、衝突の確率がどれだけ大きいのか、他の人に計算されにくいのかに関心を持っているかもしれません.php 5をダウンロードします.3.6のソースコードは/ext/sessionディレクトリに入り、session idを生成する関数はsessionにある.cファイルの345行ですが、この関数について詳しく説明します.理解のために、いくつかのコードの順序を調整しました.
phpのデフォルトsession_id生成アルゴリズムは、攻撃者がタイムスタンプ、ミリ秒数、後のランダム数を同時に当てるのに十分でない限り、比較的ランダムである.
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
{
// , ~
PHP_MD5_CTX md5_context;
PHP_SHA1_CTX sha1_context;
#if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
void *hash_context;
#endif
unsigned char *digest;
int digest_len;
int j;
char *buf, *outid;
zval **array;
zval **token;
// $_SERVER['REMOTE_ADDR']
char *remote_addr = NULL;
// timeval ,
struct timeval tv;
gettimeofday(&tv, NULL);
// , remote_ADDR , php :
//if(isset($_SERVER['REMOTE_ADDR']))
//{remote_addr = $_SERVER['REMOTE_ADDR'];}
// : cli ~
if (
zend_hash_find(
&EG(symbol_table),
"_SERVER",
sizeof("_SERVER"),
(void **) &array
) == SUCCESS
&& Z_TYPE_PP(array) == IS_ARRAY
&& zend_hash_find(
Z_ARRVAL_PP(array),
"REMOTE_ADDR",
sizeof("REMOTE_ADDR"),
(void **) &token
) == SUCCESS
)
{
remote_addr = Z_STRVAL_PP(token);
}
/* maximum 15+19+19+10 bytes */
// session id, ~
// :%.15s%ld%ld%0.8F, :
//%.15s remote_addr ? remote_addr : ""
//%ld tv.tv_sec
//%ld (long int)tv.tv_usec
//%0.8F php_combined_lcg(TSRMLS_C) * 10
spprintf(
&buf,
0,
"%.15s%ld%ld%0.8F",
remote_addr ? remote_addr : "",
tv.tv_sec,
(long int)tv.tv_usec,
php_combined_lcg(TSRMLS_C) * 10
);
// buf
// session
/*
300 : enum{
PS_HASH_FUNC_MD5,
PS_HASH_FUNC_SHA1,
PS_HASH_FUNC_OTHER
};
812 :
PHP_INI_ENTRY("session.hash_function","0",PHP_INI_ALL,OnUpdateHashFunc)
738 :
static PHP_INI_MH(OnUpdateHashFunc)
{
......
......
val = strtol(new_value, &endptr, 10);
if (endptr && (*endptr == '\0'))
{
/* Numeric value */
PS(hash_func) = val ? 1 : 0;
return SUCCESS;
}
......
......
PS(hash_func) 0, PS_HASH_FUNC_MD5。
*/
switch (PS(hash_func))
{
// md5, md5 buf 。
case PS_HASH_FUNC_MD5:
PHP_MD5Init(&md5_context);
PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));
digest_len = 16;
break;
// SHA1, SHA1 buf 。
case PS_HASH_FUNC_SHA1:
PHP_SHA1Init(&sha1_context);
PHP_SHA1Update(&sha1_context, (unsigned char *) buf, strlen(buf));
digest_len = 20;
break;
#if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
case PS_HASH_FUNC_OTHER:
if (!PS(hash_ops))
{
php_error_docref(
NULL TSRMLS_CC,
E_ERROR,
"Invalid session hash function"
);
efree(buf);
return NULL;
}
hash_context = emalloc(PS(hash_ops)->context_size);
PS(hash_ops)->hash_init(hash_context);
PS(hash_ops)->hash_update(hash_context, (unsigned char *) buf, strlen(buf));
digest_len = PS(hash_ops)->digest_size;
break;
#endif /* HAVE_HASH_EXT */
// , , E_ERROR , ~
default:
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
efree(buf);
return NULL;
}
// buf~
// , , hash_context , md5_context、sha1_context。。。。。。
efree(buf);
/*
session.entropy_file ( ) ,
ID 。
Unix /dev/random /dev/urandom。
session.entropy_length 。 0( )。
entropy_length 0, :
*/
if (PS(entropy_length) > 0)
{
#ifdef PHP_WIN32
unsigned char rbuf[2048];
size_t toread = PS(entropy_length);
if (php_win32_get_random_bytes(rbuf, (size_t) toread) == SUCCESS)
{
switch (PS(hash_func))
{
case PS_HASH_FUNC_MD5:
PHP_MD5Update(&md5_context, rbuf, toread);
break;
case PS_HASH_FUNC_SHA1:
PHP_SHA1Update(&sha1_context, rbuf, toread);
break;
# if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
case PS_HASH_FUNC_OTHER:
PS(hash_ops)->hash_update(hash_context, rbuf, toread);
break;
# endif /* HAVE_HASH_EXT */
}
}
#else
int fd;
fd = VCWD_OPEN(PS(entropy_file), O_RDONLY);
if (fd >= 0)
{
unsigned char rbuf[2048];
int n;
int to_read = PS(entropy_length);
while (to_read > 0) {
n = read(fd, rbuf, MIN(to_read, sizeof(rbuf)));
if (n hash_update(hash_context, rbuf, n);
break;
#endif /* HAVE_HASH_EXT */
}
to_read -= n;
}
close(fd);
}
// entropy_length>0
#endif
}
// , hash_final(digest, hash_context);
efree(hash_context);
break;
#endif /* HAVE_HASH_EXT */
}
/*
session.hash_bits_per_character 。
'4'(0-9,a-f),'5'(0-9,a-v), '6'(0-9,a-z,A-Z,"-",",")。
*/
if (PS(hash_bits_per_character) < 4
|| PS(hash_bits_per_character) > 6) {
PS(hash_bits_per_character) = 4;
php_error_docref(
NULL TSRMLS_CC,
E_WARNING,
"The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now"
);
}
// digest , outid
outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5)));
j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid);
efree(digest);
if (newlen) {
*newlen = j;
}
// outid
return outid;
}
phpのデフォルトsession_id生成アルゴリズムは、攻撃者がタイムスタンプ、ミリ秒数、後のランダム数を同時に当てるのに十分でない限り、比較的ランダムである.