banneer2

Réducteur d'URL tinad:

Collez l'adresse du site:

Rechercher sur le blog du grouik:

Bien que paraissant pas très "sécure", c'est quand même agréable de ne pas avoir à s'identifier systématiquement.

Je souhaite donc placer une information dans le cookie de l'utilisateur qui permettra de l'authentifier par la suite.

Ce n'est pas pour le site de la NASA, c'est pour ça qu'on va tolérer les cookies. Cependant on va tenter de répondre à quelques exigences de sécurité.

Considérations.

En cas de vol du cookies (sniffage des connexion, faille du navigateur, ou tout simplement avec une clé USB en direct sur le poste de l'utilisateur), le cookie ne doit pas permettre une authentification depuis un autre ordinateur que celui pour lequel il a été créé. Je m'appuie sur l'adrese IP. tant pis pour ceux qui n'ont pas une IP fixe, ils s'identifieront à chaque fois.

  • le cookie ne doit pas contenir d'indication sur une méthode d'authentification alternative (le formulaire identifiant mot de passe du site par exemple).
  • Changement du cookie à chaque connexion.

Mise en oeuvre.

Construisons un mini site pour le test.

Trois fichiers:

  • index.php
  • session.php
  • connectetoi.htm

par là: http://blog-du-grouik.tinad.fr/authbycookies

un fichier index.php tout simple:

<?php
 
//démarer une session sur le serveur
 
session_start();
 
if (!isset($_SESSION['is_registered'])){
	//La variable de session $_SESSION['is_registered'] n'existant pas, 
	//on appelle le script qui va lui donner une valeur:
	include("./session.php");
}
 
//$_SESSION['is_registered']=1 si l'utilisateur est authentifié
//$_SESSION['is_registered']=0 si ce n'est pas le cas
 
switch($_SESSION['is_registered']){
	case "1":
		// Il est reconnu, saluons le visiteur
		echo "<center> Bonjour, ".$_SESSION['username']."</center><br />";
		echo "<center><a href=\"./session.php?mod=deco\">se d&eacute;connecter</a></center>";
		break;
	case"0":
		// Il n'est reconu, envoyons le sur la page de loggin et d'inscription
		include("./connectetoi.htm");		
		break;
	default:
		//Si le script session.php appelé ci dessus est bien fait, ce cas est impossible
		echo "<center>Comment que t'as fait ça toi?</center>";
}
 
?>

Nous faisons un super site qui dira bonjour à l'utilisateur authentifié et qui renverra vers une page de login les autres ^^

le fichier connectetoi.htm. Il contient un formulaire de login et un formulaire d'inscription:

<form id="auth" method="POST" action="./session.php?mod=connect">
	<center>	
	<TABLE BORDER="0">
		<CAPTION>Identifiez vous:</CAPTION>
		<TR><TH>Identifiant:</TH><TD><input name="connect_id" type="text"></TD></TR>
		<TR><TH>Mot de passe:</TH><TD><input name="connect_pwd" type="password"></TD></TR>
		<TR><TH></TH><TD><input name="connect_submit" value="Se connecter" type="submit"></TD></TR>
	</table>
	</center>
</form>
 
<br/><br/>
 
<form id="inscription" method="POST" action="./session.php?mod=inscription">
	<center>	
	<TABLE BORDER="0">
		<CAPTION>Inscrivez vous:</CAPTION>
		<TR><TH>Votre identifiant</TH><TD><input name="inscription_id" type="text"></TD></TR>
		<TR><TH>Mot de passe:</TH><TD><input name="inscription_pwd" type="password"></TD></TR>
		<TR><TH>Confirmez votre mot de passe:</TH><TD><input name="inscription_pwd_confirm" type="password"></TD></TR>
		<TR><TH></TH><TD><input name="inscription_submit" value="S'inscrire" type="submit"></TD></TR>
	</table>
	</center>
</form>

Le fichier session.php qui gèrera toutes les ations relatives à l'inscription, la connection, etc...:

<?php
if (!mysql_connect('localhost', 'MySqlUsername', '**********************')) {
	echo 'Impossible de se connecter à MySQL';
	exit;
}
mysql_query("USE blogdugrouik");
 
// Generate a random character string
 
function rand_str($length = 32, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890')
{
//fonction par kyle dot florence [@t] gmail dot com 08-May-2009 10:23
//publiée là: http://php.net/manual/fr/function.rand.php
    // Length of character list
    $chars_length = (strlen($chars) - 1);
 
    // Start our string
    $string = $chars{rand(0, $chars_length)};
 
    // Generate random string
    for ($i = 1; $i < $length; $i = strlen($string))
    {
        // Grab a random character from our list
        $r = $chars{rand(0, $chars_length)};
 
        // Make sure the same two characters don't appear next to each other
        if ($r != $string{$i - 1}) $string .=  $r;
    }
 
    // Return the string
    return $string;
}
function placecookie($iduser){
	//c'est la fonction qui place un cookie chez l'utilisateur
	$valuecookie = rand_str();
	setcookie('authbycookies[value]',$valuecookie,time()+60*60*24*30,'/authbycookies/','blog-du-grouik.tinad.fr');
 
	mysql_query("UPDATE 
			test_cookies
		SET
			update_time=NOW(),
			unique_key='".md5($valuecookie)."',
			user_ip='".$_SERVER["REMOTE_ADDR"]."'
		WHERE 
		user_id='".$iduser."'");
 
}
session_start();
//par défaut:
$_SESSION['is_registered']=(int)(0);
 
 
 
switch($_GET['mod']){
	case "inscription":
 
		//Vérifier que les trois champs sont remplis
		if (($_POST['inscription_pwd']=="")||($_POST['inscription_pwd_confirm']=="")||($_POST['inscription_id']=="")){
			echo "<center><H1>Vous n'avez pas renseign&eacute; tous les champs pour l'inscription</H1></center>";			
			include("connectetoi.htm");
			die;
		}
		//vérifier la correspondance des mots de passe
		if($_POST['inscription_pwd'] <> $_POST['inscription_pwd_confirm']){
			echo "<center><H1>les mots de passe ne correspondent pas</H1></center>";			
			include("connectetoi.htm");
			die;			
		}
 
		//bon bah on inscrit l'user
		mysql_query("INSERT INTO 
				test_cookies(
					username,
					password,
					update_time)
				VALUES(
					'".mysql_real_escape_string($_POST['inscription_id'])."',
					'".mysql_real_escape_string(md5($_POST['inscription_pwd']))."',
					NOW()");		
		//et arf, on le connecte
		$_SESSION['is_registered']=(int)(1);
		$_SESSION['username']=$_POST['inscription_id'];
 
		//trouve son userid
		$result=mysql_query("SELECT 
						user_id 
					FROM
						test_cookies
					WHERE
						username='".mysql_real_escape_string($_POST['inscription_id'])."'
						AND password='".mysql_real_escape_string(md5($_POST['inscription_pwd']))."'");
 
		$row=mysql_fetch_row($result);
		//cookie
		placecookie($row[0]);
 
		header("Location: index.php");
		die;
		break;
 
	case "connect":
		//on cherche un enregisrement contenant l'username et le md5 du mot de passe
		$result=mysql_query("SELECT 
						user_id 
					FROM
						test_cookies
					WHERE
						username='".mysql_real_escape_string($_POST['connect_id'])."'
						AND password='".mysql_real_escape_string(md5($_POST['connect_pwd']))."'");
 
		$row=mysql_fetch_row($result);
		if (isset($row[0])){
			//ok
			//on enregistre la connection
			mysql_query("UPDATE test_cookies SET update_time=NOW() WHERE user_id='".$row[0]."'");
			$_SESSION['is_registered']=(int)(1);
			$_SESSION['username']=$_POST['connect_id'];
 
			//cookie
			placecookie($row[0]);
 
			//redirection			
			header("Location: index.php");
			die;
		}else{
			//fail
			$_SESSION['is_registered']=(int)(0);
			header("Location: index.php");
			die;
		}
		break;
	case "deco":
		//echo "plop";
		//setcookie('authbycookies[value]','');
		setcookie("authbycookies[value]", false, time() - 3600,'/authbycookies/','blog-du-grouik.tinad.fr'); 
		$_SESSION['is_registered']=(int)(0);
		unset($_COOKIE['authbycookies']['value']);
		session_unset();
 
		header("Location: index.php");
		die;		
		break;
	default:
 
}
 
//test de l'authentification par cookie
 
if (!isset($_COOKIE['authbycookies']['value'])){
	$_SESSION['is_registered']=(int)(0);
}else{
	$result = mysql_query("SELECT 
					user_id, 
					username
				FROM 
					test_cookies
				WHERE 
					unique_key='".md5($_COOKIE['authbycookies']['value'])."'		
					AND user_ip='".$_SERVER["REMOTE_ADDR"]."'");
	$row=mysql_fetch_row($result);
	if (isset($row[0])){	
		//ok
		//on enregistre la connection
		mysql_query("UPDATE test_cookies SET update_time=NOW() WHERE user_id='".$row[0]."'");
		$_SESSION['is_registered']=(int)(1);
		$_SESSION['username']=$_POST['connect_id'];
 
		// renouvellement du cookie
		placecookie($row[0]);
 
	}else{
		$_SESSION['is_registered']=(int)(0);
	}	
 
}
 
?>

la table dans la base de données est faite comme ça:

mysql> describe test_cookies;
+-------------+----------+------+-----+---------+----------------+
| Field       | Type     | Null | Key | Default | Extra          |
+-------------+----------+------+-----+---------+----------------+
| user_id     | int(11)  | NO   | PRI | NULL    | auto_increment | 
| username    | text     | NO   |     | NULL    |                | 
| password    | text     | NO   |     | NULL    |                | 
| update_time | datetime | NO   |     | NULL    |                | 
| unique_key  | text     | NO   |     | NULL    |                | 
| user_ip     | text     | NO   |     | NULL    |                | 
+-------------+----------+------+-----+---------+----------------+
6 rows in set (0.01 sec)

Conclusion

C'est super brouillon, et j'ai la flegme d'écrire un tutoriel là dessus. Mais ça me resservira de l'avoir à porté de main.

Commentaires

1. Le jeudi, août 26 2010, 07:05 par un flémard...
gravatar

JE trouve que ça fait beaucoup de lignes pour un cookie...
Explique moi un peu l'utilité de tout ça alors que tu pourais faire un truc du genre

if(isset$_SESSION['REMOTE_ADDR'] && $_SERVER['REMOTE_ADDR']==$_SESSION['REMOTE_ADDR'])
{
include('login.php');
//
}

avec les verrifications qui s'imposent et l'affectation de $_SESSION['REMOTE_ADDR'] dans login.php evidement...

2. Le jeudi, août 26 2010, 08:43 par gnieark
gravatar

Bonjour flémar

Mon titre est mal choisi car ce n'est pas que le cookie, mais aussi l'authentification normale là.

je l'utilise de cette manière au début des fichiers qui sont appelés par des includes. ça fait moins de code que dans votre commentaire:

if($_SESSION['is_registered']!="1")
{
echo "";
die;
}

Dans l'index.php cependant là si l'utilisateur n'est pas authentifié, je le renvoie sur la page de loggin, et ce n'est qu'une fois:

if (!isset($_SESSION['is_registered'])){
include("./session.php");
}

switch($_SESSION['is_registered']){

case "1":
//site
break;
default:
include("./connectetoi.htm"); break;
}

Ce qui revient exactement au même que votre proposition sauf que j'ai appelé votre fichier "login.php" session.php

Ajouter un commentaire

Nom ou pseudo:
Adresse email:
Site web (facultatif):
Commentaire:

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

La discussion continue ailleurs

URL de rétrolien : http://blog-du-grouik.tinad.fr/trackback/489

Fil des commentaires de ce billet

Dans la même catégorie:
dev web


Creer un tchat (chat) en AJAX php

bulle_tchat-406.jpg
Un tchat, mélangeant les techniques suivantes: javascript, AJAX, PHP, mysql et JSON, en moins de 150 lignes. Il y a quelques mois Hempstar proposait sur ce blog sa version du chat. Comme j'ai énormément progressé dans ces langages de programmation, je me demandais si je saurai le faire, en quelques

Lire la suite...



Php, générer un e-mail avec plusieurs pièces jointes.

E-mail
Voici une fonction pour envoyer un e-mail en PHP avec des pièces jointes quelque soit leur extension (ou presque). La machine qui m'a servi à faire les tests est un champs MX du domaine, et l'adresse de l'expéditeur appartient au domaine (ça aide.) Le résultat des essais: Vers une boite e-mail free

Lire la suite...


setAttribute - Patch pour internet explorer - Javascript

Internet explorer interprète mal ou pas du tout la function setAttribute. Ci dessous mon prototype à insérer en début de script pour patcher ce navigateur. Il manque surement des cas particuliers que je n'ai pas pris en compte, il suffira de rajouter des "case" dans ce prototype.

Lire la suite...


Le sélecteur de dates en javascript Version 0.3.1

calendriers.jpg
Edit du 17/11/2011, passage en version 0.3.1 pour patcher internet explorer. test ok sur IE8 et IE 9, les autres versions n'ont pas été testées. L'objet de ce codage est de permettre l'intégration simple (#feignasse) sur des sites web d'un sélecteur de date plus sexy que 3 listes déroulantes. Je me

Lire la suite...


Un filtre antispam supplémentaire pour dotclear

kill the spam
J'ai remarqué que les spammeurs qui sévissent sur mon blog, ont souvent ces deux points communs: Le nom de l'auteur contient la description du site dont il fait la promotion, souvent plus de trois mots. Il a renseigné un lien vers un site internet, évidemment. Vu que dans les commentaires légitimes,

Lire la suite...


Propulsé par Dotclear