Lorsque j'appelle session_start()
ou session_regenerate_id()
, PHP génère ce qui semble être une chaîne aléatoire pour l'ID de session. Ce que je veux savoir, c'est c'est juste une séquence aléatoire de caractères, ou est-ce comme la fonction uniqid()
?
Parce que s'il ne s'agit que de personnages aléatoires, ne pourriez-vous pas théoriquement rencontrer un conflit? Si l'utilisateur A se connectait, puis l'utilisateur B se connectait et, bien que cela soit très peu probable, l'utilisateur B générait le même ID de session, alors l'utilisateur B finirait par accéder au compte de l'utilisateur A.
Même si PHP vérifie si une session avec le même ID existe déjà et, si c'est le cas, régénère à nouveau un ID ... Je ne pense pas que je veux un système qui produit JAMAIS le même Identifiez-vous deux fois, même après la collecte des ordures - peut-être que je veux stocker une table d'entre eux et vérifier contre eux pour un éventuel détournement ou autre.
Si ce n'est pas unique, comment dois-je procéder pour appliquer l'unicité? Je préfère l'implémenter en utilisant la configuration PHP que dans tous les scripts que je crée. Une bonne chose à propos des sessions PHP ne se soucie pas des détails techniques en arrière-plan).
Si vous voulez savoir comment PHP génère un ID de session par défaut, consultez le code source sur Github . Ce n'est certainement pas aléatoire et est basé sur un hachage (par défaut: md5) de ces ingrédients (voir la ligne 310 de l'extrait de code):
Si le système d'exploitation dispose d'une source aléatoire, la force de l'ID généré dans le but d'être un ID de session est élevée (/dev/urandom et les autres sources aléatoires du système d'exploitation sont (généralement) des PRNG sécurisés cryptographiquement ). Si ce n'est pas le cas, alors c'est satisfaisant.
L'objectif de la génération d'identification de session est de:
Ceci est réalisé par l'approche de PHP à la génération de session.
Vous ne pouvez absolument pas garantir l'unicité , mais les probabilités sont si faibles de frapper deux fois le même hachage que cela ne vaut généralement pas la peine de s'inquiéter.
Voici le code qui génère l'id: Session.c
Plus précisément, le php_session_create_id
fonction:
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 = NULL;
#endif
unsigned char *digest;
int digest_len;
int j;
char *buf, *outid;
struct timeval tv;
zval **array;
zval **token;
char *remote_addr = NULL;
gettimeofday(&tv, NULL);
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 */
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);
switch (PS(hash_func)) {
case PS_HASH_FUNC_MD5:
PHP_MD5Init(&md5_context);
PHP_MD5Update(&md5_context, (unsigned char *) buf, strlen(buf));
digest_len = 16;
break;
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 */
default:
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid session hash function");
efree(buf);
return NULL;
}
efree(buf);
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, MIN(toread, sizeof(rbuf))) == 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 <= 0) break;
switch (PS(hash_func)) {
case PS_HASH_FUNC_MD5:
PHP_MD5Update(&md5_context, rbuf, n);
break;
case PS_HASH_FUNC_SHA1:
PHP_SHA1Update(&sha1_context, rbuf, n);
break;
#if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
case PS_HASH_FUNC_OTHER:
PS(hash_ops)->hash_update(hash_context, rbuf, n);
break;
#endif /* HAVE_HASH_EXT */
}
to_read -= n;
}
close(fd);
}
#endif
}
digest = emalloc(digest_len + 1);
switch (PS(hash_func)) {
case PS_HASH_FUNC_MD5:
PHP_MD5Final(digest, &md5_context);
break;
case PS_HASH_FUNC_SHA1:
PHP_SHA1Final(digest, &sha1_context);
break;
#if defined(HAVE_HASH_EXT) && !defined(COMPILE_DL_HASH)
case PS_HASH_FUNC_OTHER:
PS(hash_ops)->hash_final(digest, hash_context);
efree(hash_context);
break;
#endif /* HAVE_HASH_EXT */
}
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");
}
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;
}
return outid;
}
Comme vous pouvez le voir, l'identifiant réel est un hachage d'un mélange de choses, comme l'heure de la journée. Il y a donc une possibilité de se heurter à un conflit, cependant, il a une possibilité très faible. Tant et si bien, cela ne vaut la peine de s'inquiéter que si vous avez beaucoup d'utilisateurs simultanés.
Cependant, si vous êtes vraiment inquiet, vous pouvez augmenter l'entropie en définissant un algorithme de hachage différent session.hash_function
En ce qui concerne le suivi des sessions actives, cette question le couvre bien Est-il possible de voir les sessions actives en utilisant php?
Si vous utilisez une seule instance de php sur une seule machine, il dispose en fait d'un gestionnaire de sessions intégré qui vérifie si un identifiant existe déjà avant de l'attribuer. Cependant, si vous exécutez plusieurs instances ou plusieurs machines, il n'a aucun moyen de savoir quels ID ont été attribués par d'autres machines.