IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Token , session et bug incompréhensible [PHP 5.3]


Sujet :

Langage PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 693
    Par défaut Token , session et bug incompréhensible
    Bonjour à tous,

    J'ai une classe me permettant de générer des "token" pour sécurisé divers appel à des formulaire ou des appels ajax.
    Je n'avais jusqu'à maintenant jamais eu de problème. Or je viens de tester la classe sur un hébergement mutualisé et là c'est le drame !

    Le concept : On arrive sur un formulaire , un token est généré, stocké en session puis plaer dans un input hidden.
    Après soumission du formulaire , je vérifie si le token en session est équivalent à celui passé dans le formulaire.

    Le problème : La valeur en session est modifiée entre le clic sur le bouton d'envoi et l'apparition de la page du coup le token n'est jamais le bon.

    J'ai retourné le code dans tous les sens mais rien à faire. Un petit exemple simplifié ou je rencontre le problème :

    Token.class.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    class Util_Token
    {
    	static public $error = 0;
     
    	static public function genToken($ttl = 15)
    	{
    		if(!isset($_SESSION))
    			throw new Exception("Une session doit être active");
     
     
    		$gentoken 	= hash('sha1',uniqid(rand(),true));
    		$rand 		= rand(1,20);
    		$gentoken	= substr($gentoken,$rand,20);
    		$ttl		*= 60;
     
    		$_SESSION['csrf_protect'] = array('token'=>$gentoken,'ttl'=>$ttl);
     
    		return $gentoken;
    	}
     
    	static public function checkToken()
    	{
    		if(!isset($_SESSION))
    			throw new Exception("Une session doit être active");
     
    		if($_REQUEST['csrf_protect'] == $_SESSION['csrf_protect']['token'])
    			return true;
    		else
    			return false;
    	}
    }
    index.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    session_start();
    require('Token.class.php');
    if(!empty($_POST) || !empty($_GET))
    {
    	echo 'Recu Form : '.$_POST['csrf_protect'].'<br />';
    	echo 'Connu Session : '.$_SESSION['csrf_protect']['token'].' ttl : '.$_SESSION['csrf_protect']['ttl'].'<br />';
     
    }
    else
    {
    $token = Util_Token::genToken();
     
    echo 'Généré : '.$token;
    ?>
    <form action="index.php" method="post">
    	<input type="text" value=" TEst" name="testtext">
    	<input type="hidden" value="<?php echo $token; ?>" name="csrf_protect">
    	<input type="submit" value="envoi" />
    </form>
    <?php
    }
    ?>
    En remplacant la chaine aléatoire du token par une date (H:i:s) j'ai remarqué que sur le serveur mutualisé il y'avais 1 sec de décalage entre la date recu et la date en session.

    Note : En local je n'ai pas de problème avec ce code...
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  2. #2
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Salut

    D'abord, je n'est pas de solution, je ne vois pas trop la raison
    Ca commence mal

    Est ce que code que tu donne est un code simplifié de ce que tu as où est-ce réellement ce code que tu as ?

    Il y a un truc où il me semble intéressant de confirmer, c'est est ce que lors de la création du token et de son affichage dans le champ caché les dates sont vraiment identiques ?
    Ce qui laisserait supposer que ce serait vraiment lors de la récupération de celui-ci qui cause problème (le session_start).


    Après ça, une idée comme ça pour débugger (donc provisoirement), il n'y aurait il pas moyen de rajouter un code dans la méthode genToken() qui écrirait dans un fichier par exemple afin de savoir l'heure exacte de chaque appel, mais surtout savoir combien de fois il y a eu d'appel.
    Sait on jamais, cette méthode est peut être appelée 2 fois soit à une intervalle d'une seconde (qui modifierait sa valeur).
    Un simple appel à error_log('une date') suffirait dans un tel cas.



    Disons que, il serait bon d'avoir la certitude que c'est lors de l'appel à session_start() où le décalage à lieu.
    Si décalage il y a, donc qu'au départ c'est bon puis après c'est plus bon, il y a forcément "écrasement" de cette valeur à un moment donné, non ?
    (faut même souhaité que ce soit le cas, sinon c'est THE big bug, la grosse tuile même )
    Je me dis que dans tel cas, il faudrait repérer qui modifie cette variable "token" de session, voir la session elle même (le fichier).


    Je me suis jamais trop posé ce genre de question, mais il y a t-il quelque part une trace (un log) de tout accès à un fichier, surtout s'il est modifié, comme entre autre les fichiers de sessions ? (Apache, Php, etc ... ?)

    Puis à 200% au pif : As tu essayé de changer les valeurs des clés (csrf_protect, token) ?



    Plutôt surprenant ce décalage, et particulièrement que ça marche en local et pas sur un mutualisé.

  3. #3
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 693
    Par défaut
    Est ce que code que tu donne est un code simplifié de ce que tu as où est-ce réellement ce code que tu as ?
    C'ets un code simplifié mais j'ai extrait que la partie qui pose problème. Le reste (méthode static) n'intervient pas dans le problème.

    Comme tu le préconisais j'ai fait un trace dans un fichier texte. Code utilisé :

    Token.class.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Util_Token
    {
    	static public $error = 0;
     
    	static public function genToken($ttl = 15)
    	{
    		if(!isset($_SESSION))
    			throw new Exception("Une session doit être active");
     
    			$gentoken 	= hash('sha1',uniqid(rand(),true));
    			$rand 		= rand(1,20);
    			$gentoken	= substr($gentoken,$rand,20);
    			$ttl		*= 60;
    			$h = fopen('test.txt','a+');
    			fwrite($h,date("H:i:s").' :  '.$gentoken."\n");
    			fclose($h);
    			$_SESSION['csrf_protect'] = array('token'=>$gentoken,'ttl'=>$ttl);
     
    			return $gentoken;
    	}
    }
    index.php
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    session_start();
    require('Token.class.php');
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    </head>
    <body>
    <?php
    if(isset($_POST) && !empty($_POST))
    {
    	echo 'Recu Form : '.$_POST['csrf_protect'].'<br />';
    	echo 'Connu Session : '.$_SESSION['csrf_protect']['token'].' ttl : '.$_SESSION['csrf_protect']['ttl'].'<br />';
     
    }
    else
    {
    	$token = Util_Token::genToken();
    	echo 'Généré : '.$token;
    	?>
    	<form action="index.php" method="post">
    		<input type="text" value=" TEst" name="testtext">
    		<input type="hidden" value="<?php echo $token; ?>" name="csrf_protect">
    		<input type="submit" value="envoi" />
    	</form>
    <?php
    }
    ?>
    </body>
    </html>
    Donc je peux pas faire plus basique.
    En local et sur un dédié (Php 5.3.3) Mon fichier texte contient bien le résultat attendu :
    08:35:15 - montokensupersecret
    Par contre sur le mutualisé (ovh 5.2.14) j'hallucine complètement :
    08:33:17 - montokensupersecret #Correspond au chargement normal de la page
    08:33:17 - unautretoken
    08:33:20 - encoreuntoken # correpsond à l'appui sur le bouton submit
    Donc deux appels en trop qui sorte de nul part alors que le code utilisé est strictement identique.

    J'avoue ne pas comprendre.

    Edit ---
    Testé sur un mutu 1and1 et le problème est présent également. LA seule différence entre les mutu et mon poste locale/serveur dédié c'est l'os (Linux pour les mutu , windows pour les dédiés)

    Edit2 ----

    Même le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    session_start();
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    </head>
    <body>
    <?php
    if(isset($_POST) && !empty($_POST))
    {
    	echo 'Recu Form : '.$_POST['csrf_protect'].'<br />';
    	echo 'Connu Session : '.$_SESSION['csrf_pro']['token'].' ttl : '.$_SESSION['csrf_pro']['ttl'].'<br />';
     
    }
    else
    {
    	/*require_once('Token.class.php');
    	$token = Util_Token::genToken();*/
    	function genToken()
    	{
    		$h = fopen('test.txt','a+');
    		fwrite($h,date("H:i:s")."\n");
    		fclose($h);
    	}
    	$qsd = genToken();
    	?>
    	<form action="index.php" method="post">
    		<input type="text" value=" TEst" name="wxvxcvb">
    		<input type="hidden" value="<?php echo $qsd; ?>" name="wxc">
    		<input type="submit" value="envoi" />
    	</form>
    <?php
    }
    ?>
    </body>
    </html>
    Génère 3 lignes dans le fichiers texte ...
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    C'est clairement bizarre.

    Il y un truc où je n'ai pas de réel explication, mais cette condition me chiffonne un peu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(!isset($_SESSION))
    C'est peut être pas du tout le problème, mais pour exemple, de mon coté j'ai plutôt créé une méthode Session::isStarted() (true/false) qui me permets de vérifier si la session a bien démarrée.


    Aussi, tu avais évoqué Ajax dans ton 1er post.
    Du coup, n'y aurait il pas justement une vérification via Ajax des données saisie du formulaire, qui théoriquement initialiserait/démarrerait la session ?
    Si tel est le cas, il y a peut être quelque chose de particulier (Ajax c'est déjà particulier).

    Puis coté traçage (vu que je patauge aussi sur ce problème), personnellement je ferais en sorte d'y rajouter le nom de la page qui appel le script.
    Histoire d'être certain que c'est cette page (ou vue) formulaire.


    As tu relevé les logs coté Apache ?
    N'y aurait il pas des requêtes HTTP envoyées comme ça anormalement ?


    Vu que ça à l'air une question de version de Php, comme ça je me dis qu'il doit avoir une erreur pour cette version et pas sur celle en local.
    Cette erreur provoquerait donc ces 2 appels de trop.
    Mais alors quoi ???


    Juste comme ça, je ne vois nulle par l'initialisation/déclaration de cette variable .ttl.
    Théoriquement ça devrait provoquer une erreur, non ?
    Je sais que ça n'a rien avoir, mais comme d'hab, sait on jamais.


    Toujours pas de solution, j'en sais fichetre rien

  5. #5
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Tiens donc ?
    Ca me rappel quelque chose ça.

    L'URL est elle vraiment comme ça : index.php
    Essai de plutôt mettre comme ceci : /index.php, ou mettre une URL absolue complète.

    Je n'entrerais pas dans les détails, mais j'ai eu un bug franchement tordu (et bien prise de tête) en exploitant justement des URLs comme ça (index.php) alors qu'en mettant le slash avant, plus du tout de problème.

    Même crédo, sait on jamais.

  6. #6
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 693
    Par défaut
    Aussi, tu avais évoqué Ajax dans ton 1er post.
    Du coup, n'y aurait il pas justement une vérification via Ajax des données saisie du formulaire, qui théoriquement initialiserait/démarrerait la session ?
    Dans mes tests je suis sur un simple formulaire pas d'ajax

    Puis coté traçage (vu que je patauge aussi sur ce problème), personnellement je ferais en sorte d'y rajouter le nom de la page qui appel le script.
    Histoire d'être certain que c'est cette page (ou vue) formulaire.
    Bonne idée mais ca ne m'avance pas plus :

    10:23:36 /labs/token/index.php
    10:23:36 /labs/token/index.php
    10:23:39 /labs/token/index.php
    Tiens donc ?
    Ca me rappel quelque chose ça.

    L'URL est elle vraiment comme ça : index.php
    Essai de plutôt mettre comme ceci : /index.php, ou mettre une URL absolue complète.
    Déjà eu ce style de problème également mais là ca ne semble pas pose rde problème (les deux solutions rencontre le même souçis).

    Si jamais certains peuvent tester ce simple bout de code et vérifié qu'il ne produit pas 3 lignes mais bien une seule :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    session_start();
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
    </head>
    <body>
    <?php
    if(isset($_POST) && !empty($_POST))
    {
    	echo 'Formulaire envoyé ,consulter fichier log';
     
    }
    else
    {
    	/*require_once('Token.class.php');
    	$token = Util_Token::genToken();*/
    	function genToken()
    	{
    		$h = fopen('test.txt','a+');
    		fwrite($h,date("H:i:s").' '.$_SERVER['REQUEST_URI']."\n");
    		fclose($h);
    	}
    	$qsd = genToken();
    	?>
    	<form action="index.php" method="post">
    		<input type="text" value=" TEst" name="wxvxcvb">
    		<input type="hidden" value="<?php echo $qsd; ?>" name="wxc">
    		<input type="submit" value="envoi" />
    	</form>
    <?php
    }
    ?>
    </body>
    </html>
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Invité de passage
    Homme Profil pro
    cariste ;p
    Inscrit en
    Janvier 2013
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : cariste ;p
    Secteur : Bâtiment

    Informations forums :
    Inscription : Janvier 2013
    Messages : 1
    Par défaut
    Comme le sujet n'est pas en résolut , j'ai ptet une petite idée

    j'ai eu un problème similaire lors d'appel de script jquery avec le session_start :

    l'id de session changeait lorsque j'appelais un fichier php contenant un script jquery, alors que je n'y faisait qu'a peine référence.... ce qui n'est pas ultra pratique ni logique

    je me suis aperçu (après de nombreux tests ) que c'était la variable de récupération dans le script php appelé qui modifiait la valeur de la variable dans la session

    une petite explication :

    script appelant:

    <a href="#?i=1" class="Artisants__voir bouton_action"><img src="ui/icones/voir.png" title="Voir" width="24">Voir</a>

    // voir
    $(".Artisants__voir").click(function(){
    var id=this.href.split(/(.+)i=([^&]+)/)[2];
    var link="t='.$tab.'&i="+id;
    alert("voir appuyé = "+link);
    $.ajax({
    type:"POST",
    url:"'.$config['path']['jquery'].'/moteur/Detail.php",
    data:link,
    success:function(data){ $("#Artisants_Core").html(data); }
    });
    });

    et dans le script appelé (Detail.php) :

    if (isset($_POST['i'])){$id=$_POST['i'];}

    là tout partait de travers et l'id de session devenait égal à l'id de l'item visité
    j'ai juste changé le nom de la variable de récupération

    if (isset($_POST['i'])){$i=$_POST['i'];}

    et la plus de problème

    En espérant que ca puisse à certain de résoudre ce bug étonnant

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Bug incompréhensible IE6
    Par Lideln75 dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 19/06/2009, 10h22
  2. J'ai besoin d'aide concernant un bug incompréhensible
    Par Kicker dans le forum GTK+ avec C & C++
    Réponses: 22
    Dernier message: 23/05/2008, 13h27
  3. [PC] Sockets avec API win32, bug incompréhensible
    Par ValyGator dans le forum Windows
    Réponses: 4
    Dernier message: 27/02/2008, 17h13
  4. bug incompréhensible
    Par petdelascar dans le forum MFC
    Réponses: 4
    Dernier message: 19/11/2005, 19h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo