Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Passage php4 vers php5

61 réponses
Avatar
Yannick
Bonjour,

N'étant pas très doué je n'arrive pas à modifié les 3 scripts suivants.
Il fonctionne très bien sous php4 mais rien à faire sous php5.
1) la recherche ne se fait pas
2) l'affichage dans le pop est vide

Merci à celui qui voudras bien me résoudre cet incident.

Amitiés

Début des scripts

INDEX.PHP

<?php /* echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?".">"; */?>
<?
//INCLUSION DU FICHIER DE CONNEXION
include("connect.inc");

//CONNEXION A LA BASE
$mysql_id=mysql_connect($server,$user,$pwd);

// Sortir du script en cas de problème de connexion
//au serveur.
if(!$mysql_id){
echo "Problème de connexion à la base : ".mysql_errno().":
".mysql_error()."<br />";
exit;
}

//SELECTION DE LA BASE
mysql_select_db($base,$mysql_id);

//SELECTION DE LA TABLE
$table = 'FP_Complet';

//CONSTRUCTION DE LA CLAUSE 'WHERE'
if ($nom){ // Si un nom est inscrit dans le formulaire
$where=" WHERE nom LIKE '%".$nom. "%'";
if ($prenom){ // Si le prénom est aussi renseigné
$where=" WHERE nom='".$nom."' AND prenom LIKE '%".$prenom. "%'";
}
}
else{ // Les deux champs sont vides
$where="";
}

//CONSTRUCTION DE LA CLAUSE 'LIMIT'
//Nombre d'enregistrements souhaités par page
$nb_par_page=10;

if (!$page){
$ligne_debut=0;
}
else{
$page=$page-1;
$ligne_debut=$page*$nb_par_page;
}

$limit=" LIMIT ".$ligne_debut.", ".$nb_par_page;

//REQUETE SQL
$qry="SELECT * FROM $table".$where." ORDER BY nom " .$limit;
//echo $qry;

//EXECUTION DE LA REQUETE
$result=mysql_query($qry);

$nb_pages=($nb_fiches_max/$nb_par_page);
$nb_pages=ceil($nb_pages);

//CALCUL DU NOMBRE DE PAGES

if (!$nb_pages) { // Si le nb de pages n'a encore jamais été calculé

if ($nom){
$nb_fiches_max=mysql_num_rows($result);
}
else{
$qry2="SELECT * FROM $table";
//echo $qry2;
$result2=mysql_query($qry2);
$nb_fiches_max=mysql_num_rows($result2);
}
$nb_pages=($nb_fiches_max/$nb_par_page);
$nb_pages=ceil($nb_pages);
}

// MESSAGE AU DESSUS DU TABLEAU
if ($nb_fiches_max > 0){ //S'il y a au moins un résultat
$page=$page+1;
$msg= "page ".$page." sur ".$nb_pages; //On affiche le nombre de
pages sur le total
}
else{
$msg="Désolé, aucun enregistrement trouvé !"; //Sinon, on signale
qu'il n'y a pas de résultats
}
?>

<!DOCTYPE php PUBLIC "-//W3C//DTD Xphp 1.1//EN"
"http://www.w3.org/TR/xphp11/DTD/xphp11.dtd">
<php xmlns="http://www.w3.org/1999/xphp" xml:lang="fr">
<head>
<title>Fonctionnaires</title>
<meta http-equiv="Content-Type" content="text/php; charset=iso-8859-1" />
<style type="text/css">

body{
background-color:#ffffff;
font-family: Trebuchet MS,Verdana,Geneva,Arial,Helvetica,sans-serif;
}
table.result{
font-family:Arial,sans-serif;
border-collapse:collapse;
border:1px solid #333333;
margin-top:10px;
width:780px;
text-align: center;
}
td.nom {
padding:5px;
width: 200px;
border:1px solid #333333;
text-align: center;
background-color:#087417;
color:#ffffff;
}
td.prenom {
padding:5px;
width: 250px;
border:1px solid #333333;
text-align: center;
background-color:#087417;
color:#ffffff;
}
td {
border:1px solid #333333;
padding:3px;
text-align: left;
}
span.page{
padding-left: 10px;
}
div.pages{
text-align: center;
padding-top: 5px;
}
</style>
</head>
<div align="center">
<body bgcolor="#E7FFB3"><h1>Les fonctionnaires dans les registres</h1>
Vous trouverez ici les donn&eacute;es de fonctionnaires vues dans
les registres.<br>
<strong>Pourquoi cette base?</strong><br>
Le fait que les fonctionnaires soient appelés à se déplacer les rends
difficilement localisables.<br>
<br>
</div><center>
<?
##########################
# Recherche infos pour affichage des infos completes

$r=mysql_query("SELECT id FROM $table ORDER by id DESC LIMIT 1 " );
while($row =mysql_fetch_array($r))
{
echo ("<b><p>Il y a "); ?>
<font color="#006599">
<? echo (" $row[id] "); ?>
</font>
<? echo (" entrées dans la base <br> "); }

//$r=mysql_query("SELECT nom, id FROM $table ORDER by id LIMIT 1 ");
// while($row =mysql_fetch_array($r))
// {
// echo ("Pour "); ?>
<font color="#006599">
<? // echo (" $row[id] "); ?>
</font>
<?// echo (" patronymes dans la base<br></b>"); }
?>


<!-- FORMULAIRE -->
<form action="FP_adh.php" method="get" class="page">
<table align="center" style="border:0px;">
<tr>
<td style="border:0px;">NOM</td>
<td style="border:0px;"><input type="text" name="nom"
value="<?echo $nom?>" /></td>
<td style="border:0px;">Prénom</td>
<td style="border:0px;"><input type="text" name="prenom"
value="<?echo $prenom?>" /></td>
<td style="border:0px;"><input type="submit" name="submit"
value="Rechercher" /></td>
</tr>
</table>
</form>

</div>
<!-- FIN FORMULAIRE -->
<br><br>
Interrogez la base par départements<br>
<a href="FP_cartes.php">Lieux des registres</a><br>
<a href="FP_cartes_n.php">Lieux de naissances</a><br>
Lieux de décès à l'étude
<br>
<?php
echo "<br />\n"; //On passe une ligne
include ('../../Pied_page.php'); ?>
</center>
</body>
</html>



<?php /* echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?".">"; */?>
<?php
//INCLUSION DU FICHIER DE CONNEXION
include("connect.inc");

//CONNEXION A LA BASE
$mysql_id=mysql_connect($server,$user,$pwd);

// Sortir du script en cas de problème de connexion
//au serveur.
if(!$mysql_id){
echo "Problème de connexion à la base : ".mysql_errno().":
".mysql_error()."<br />";
exit;
}

//SELECTION DE LA BASE
mysql_select_db($base,$mysql_id);

//SELECTION DE LA TABLE
$table = 'FP_Complet'; // Le nom de cette table ne passe pas chez Sivit !

//CONSTRUCTION DE LA CLAUSE 'WHERE'
if ($nom){ // Si un nom est inscrit dans le formulaire
$where=" WHERE Nom LIKE '%". $nom. "%'";
if ($prenom){ // Si le prénom est aussi renseigné
$where=" WHERE nom='". $nom."' AND prenom LIKE '%".$prenom. "%'";
}
}
else{ // Les deux champs sont vides
$where="";
}

//CONSTRUCTION DE LA CLAUSE 'LIMIT'
//Nombre d'enregistrements souhaités par page
$nb_par_page=50;

if (!$page){
$ligne_debut=0;
}
else{
$page=$page-1;
$ligne_debut=$page*$nb_par_page;
}

$limit=" LIMIT ".$ligne_debut.", ".$nb_par_page;

//REQUETE SQL
$qry="SELECT * FROM $table".$where." ORDER BY nom " .$limit;
//echo $qry;

//EXECUTION DE LA REQUETE
$result=mysql_query($qry);

$nb_pages=($nb_fiches_max/$nb_par_page);
$nb_pages=ceil($nb_pages);

//CALCUL DU NOMBRE DE PAGES

if (!$nb_pages) { // Si le nb de pages n'a encore jamais été calculé

if ($nom){
$nb_fiches_max=mysql_num_rows($result);
}
else{
$qry2="SELECT * FROM $table";
//echo $qry2;
$result2=mysql_query($qry2);
$nb_fiches_max=mysql_num_rows($result2);
}
$nb_pages=($nb_fiches_max/$nb_par_page);
$nb_pages=ceil($nb_pages);
}

// MESSAGE AU DESSUS DU TABLEAU
if ($nb_fiches_max > 0){ //S'il y a au moins un résultat
$page=$page+1;
$msg= "page ".$page." sur ".$nb_pages; //On affiche le nombre de
pages sur le total
}
else{
$msg="Désolé, aucun enregistrement trouvé !"; //Sinon, on signale
qu'il n'y a pas de résultats
}
?>

<!DOCTYPE php PUBLIC "-//W3C//DTD Xphp 1.1//EN"
"http://www.w3.org/TR/xphp11/DTD/xphp11.dtd"><head>
<title>Fonctionnaires</title>

<center><h1>Les fonctionnaires dans les registres</h1></center>
<?php
echo $msg."\n"; // On écrit le message au dessus du tableau
?>


<!-- EN-TÊTES DU TABLEAU -->
<center>
Pour obtenir les informations complètes vous devez accepter les 'pop-up'
de ce site<br><br>
Cliquez sur la ligne de votre choix.
<link rel="stylesheet" href="base_resultat.css" type="text/css">

<table class="result">
<tr>
<td class="nom"><strong><font size="3">Nom</font></strong></td>
<td class="prenom"><strong><font size="3">Prénom</font></strong></td>
<td class="date_N"><strong><font size="3">Date
Naissance</font></strong></td>
<td class="lieu_N"><strong><font size="3">Lieu
Naissance</font></strong></td>
<td class="dpt_N"><strong><font size="3">Département
Naissance</font></strong></td>
</tr>

<!-- FIN EN-TÊTES DU TABLEAU -->

<!-- REMPLISSAGE DU TABLEAU -->

<?php
while($row=mysql_fetch_object($result)){
echo "<tr style=\"cursor: hand;\"
onmouseover=\"this.style.backgroundColor='#6C81B9'\"
onmouseout=\"this.style.backgroundColor = ''\"
onclick=\"javascript:window.open('pop_FP_adh.php?id=$row->id&choixpop_FP_adh','width=480,height=300,left=0,top=0,toolbar=no,menubar=no,resizable=no,scrollbars=yes');return(false)\">\n";
echo "<td>$row->nom</td>\n";
echo "<td>$row->prenom</td>\n";
echo "<td>$row->date_n</td>\n";
echo "<td>$row->lieu_n</td>\n";
echo "<td>$row->dpt_n</td>\n";
echo "</tr>\n";
}
?>

</table>
</center>
<!-- FIN REMPLISSAGE DU TABLEAU -->
</div>

<!-- LIENS VERS LES AUTRES PAGES -->
<div align="center" class="pages">
<?php
$i=0;
while ($i <= $nb_pages-1):
$j=$i+1;
if ((!$nom) AND (!$prenom)){
echo "<span class=\"page\"><a
href=\"FP_adh.php?page=".$j."&nb_pages=".$nb_pages."\">".$j."</a></span>\n";
}
else if (($nom) AND ($prenom)) {
echo "<span class=\"page\"><a
href=\"FP_adh.php?page=".$j."&nb_pages=".$nb_pages."&nom=".$nom."&prenom=".$prenom."\">".$j."</a></span>\n";
}
else{
echo "<span class=\"page\"><a
href=\"FP_adh.php?page=".$j."&nb_pages=".$nb_pages."&nom=".$nom."\">".$j."</a></span>\n";
}
$i++;
endwhile;
?>
</div>
<!-- FIN LIENS VERS LES AUTRES PAGES -->
<?php
echo "<br />\n"; //On passe une ligne
include ('../../Pied_page.php'); ?>
</body>
</html>




<?
//INCLUSION DU FICHIER DE CONNEXION
include("connect.inc");

//CONNEXION A LA BASE
$mysql_id=mysql_connect($server,$user,$pwd);

// Sortir du script en cas de problème de connexion
//au serveur.
if(!$mysql_id){
echo "Problème de connexion à la base : ".mysql_errno().":
".mysql_error()."<br />";
exit;
}

//SELECTION DE LA BASE
mysql_select_db($base,$mysql_id);

//SELECTION DE LA TABLE
$table = 'FP_Complet'; // Le nom de cette table ne passe pas chez Sivit !

//REQUETE SQL
$qry="SELECT * FROM $table WHERE id='".$id."'";
//echo $qry;

//EXECUTION DE LA REQUETE
$result=mysql_query($qry);

//AFFECTATION DES VALEURS RENVOYEES AUX VARIABLES
while($row=mysql_fetch_object($result)){
$adh_nom_prenom=$row->adh_nom_prenom;
$adh=$row->adh;
$depot=$row->depot;
$dpt_depot=$row->dpt_depot;
$cote=$row->cote;
$prenom=$row->prenom;
$date_n=$row->date_n;
$lieu_n=$row->lieu_n;
$dpt_n=$row->dpt_n;
$titre=$row->titre;
$nom=$row->nom;
$profession=$row->profession;
$acte=$row->acte;
$qualite=$row->qualite;
$date_acte=$row->date_acte;
$description=$row->description;
$commentaire=$row->commentaires;
}

//DECLARATIONS DES FONCTIONS RIGHT ET LEFT QUI N'EXISTENT PAS EN PHP !
function left($chaine,$num) {
return substr($chaine,0,$num);
}

function right($chaine,$num) {
return substr($chaine,-$num);
}
?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<title>Fonctionnaires</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">

body{
background-color:#FEE7FE;
font-family: Trebuchet MS,Verdana,Geneva,Arial,Helvetica,sans-serif;
}
span.bold{
font-weight: bold;
}
a:link {
color: #0A42A7;
text-decoration:underline;
padding-right: 6px;
padding-left: 6px;
}
a:visited {
color: #0A42A7;
text-decoration:underline;
padding-right: 6px;
padding-left: 6px;
}
a:hover{
text-decoration:none;
color:#0A42A7;
padding-right: 6px;
padding-left: 6px;
}
</style>
</head>
<body bgcolor="#FFDFFC">
<div align="center"><h1>Les fonctionnaires dans les registres</h1>
<h3 style="text-align: center">Ensemble des informations sur</h3>
<h2 style="text-align: center;"><? echo $nom." ".$prenom;?></h2>
<? //dépôt?>
<div style="padding-left: 15px;"><span class="bold">Dépôt :
</span><span><? echo $depot." ".$dpt_depot;?></span></div>

<hr width="50%" />
<?
//Cote
if ($cote){
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Cote du
document: </span><span>$cote</span></div>";
}

//Titre
if ($titre){
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Titre du
document: </span><span>$titre</span></div>";
}
?>
<hr width="50%" />
<?
//Profession
if ($profession){
echo "<div style=\"padding-left: 15px;\"><span
class=\"bold\">Profession: </span><span>$profession</span></div>";
}

//LIGNE NAISSANCE
if (($date_n) AND ($lieu_n) AND ($dpt_n)) { // Si le lieu et la date de
naissance sont présents
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Né le
</span><span>$date_n</span><span class=\"bold\"> à
</span><span>$lieu_n</span> (<span>$dpt_n</span>)</div>";
}
else if (($date_n) AND (!$lieu_n) AND ($dpt_n)){ // Si la date de
naissance est présente mais pas le lieu
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Né le
</span><span>$date_n</span> dans le <span>$dpt_,</span></div>";
}
else if ((!$date_n) AND ($lieu_n) AND ($dpt_n)){ // Si le lieu est
présent sans la date de naissance (si ça existe ;-))
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Né à
</span><span>$lieu_n</span> (<span>$dpt_n</span>)</div>";
}

// Type acte
if ($acte){
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Type
d'acte: </span><span>$acte</span></div>";
}

// Date de l'acte
if ($date_acte){
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Date de
l'acte: </span><span>$date_acte</span></div>";
}

// Qualité
if ($qualite){
echo "<div style=\"padding-left: 15px;\"><span class=\"bold\">Qualité:
</span><span>$qualite</span></div>";
}
?>
<hr width="50%" />
<?

// Description
if ($description){
echo "<div style=\"padding-left: 15px;\"><span
class=\"bold\">Description de
l'acte:<br></span><span>$description</span></div>";
}

// Commentaires
if ($commentaire){
echo "<div style=\"padding-left: 15px;\"><span
class=\"bold\">Commentaires:</span><br><span>$commentaire</span></div>";
}
?>
<hr width="50%" />
<div align="center"><font size="-2">Informations relevées par: <? echo
$adh_nom_prenom;?></font>
</div>
<br>
<? include('../../Pied_page.php');?>
</body>
</html>

10 réponses

1 2 3 4 5
Avatar
Olivier Miakinen
Bonjour,

Le 10/04/2009 01:38, Mickael Wolff a écrit :

Imaginons que nous ayons le formulaire suivant dans notre application :

<form action='#' method='post'>
<p>
<input type='hidden' name='action' value='news.delete' />
<input type='hidden' name='id' value='42' />
<input type='submit' value='Supprimer' />
</p>
</form>



Ahem... c'est tout ? Il n'y a pas un petit id de session quelque
part dans le formulaire ? Mettons par exemple :
<input type='hidden' name='sessid' value='45ef0063d0aab7f39199' />

Ce formulaire permet de supprimer une news :



Ah oui, c'est sûr que s'il suffit d'envoyer un paramètre fixe
(news.delete) et un numéro d'article pour effacer l'article en
question, il n'est pas très difficile à un attaquant de demander
cet effacement. Mais note que le faire avec WGET en POST n'est
pas beaucoup plus difficile qu'en GET.

<?php

if(isset($_POST['action']))
{
$action = $_POST['action'] ;
if($action === 'news.delete')
{
// on traite la suppression de la news
}
}

?>



Je ne connais pas la syntaxe de WGET pour envoyer cette requête, mais si
tu y tiens je veux bien la chercher.

Si on avait utiliser $_REQUEST, que les données soient soumises en
GET ou en POST n'a pas d'importance. Dans ce cas là, un attaquant
pourrait transmettre un lien forgé à une victime utilisatrice du site :

<http://example.com/?action=news.delete&idB>

Ce lien peut ^etre explicite (dans un courriel par exemple), ou caché
(et chargé automatiquement) dans une page HTML visitée par l'utilisateur
alors qu'il est connecté à l'application compromise. On peut cacheer
dans une balise img, stype, script, etc. Bien s^ur, le HTML peut ^etre
caché dans le courriel...



Ah, je crois que je comprends enfin où peut être le problème : c'est
quand l'id de session se trouve dans un cookie. Oui, en effet dans ce
cas là un lien envoyé par courriel à quelqu'un déjà connecté pourrait
faire ce genre de chose. Mais ne peut-on faire la même chose avec un
formulaire dans un courriel en HTML ? La seule vraie protection serait
alors de mettre un id non devinable dans un champ caché du formulaire.

Moralité, ce n'est pas parce que le programmeur tordu du site a
décidé d'utiliser un nom commun entre les paramètres HTTP (COOKIE
compris) qu'il faut distinguer POST et GET, mais parce qu'un attaquant
peut ^etre tordu et profiter de la na"iveté de chacun pour nuire.



J'attends encore d'être complètement convaincu qu'un attaquant peut
amener la victime à faire par GET quelque chose qu'il ne pourrait pas
lui faire faire par POST.

Je vous conseille à tous la lecture du très bon « Sécurité PHP 5 et
MySQL » qui détaille ce genre de trous de sécurité auquelles on ne peut
que difficilement imaginer. A moins d'^etre tordu ;)

<http://www.eyrolles.com/Informatique/Livre/securite-php-5-et-mysql-9782212121148>



Merci !
Avatar
Patrick Mevzek
Le Thu, 09 Apr 2009 23:38:55 +0000, Mickael Wolff a écrit:
Sylvain SF wrote:
tu peux expliciter ce qui te parait manquer ?



Ben la distinction entre les méthodes. Utiliser $_REQUEST revient à
reproduire le comportement stupide de register_global,



Strictement AUCUN rapport !

Le problème du register_global est de fusionner deux contextes qui n'ont
rien à voir : celui de l'environnement Web (les échanges avec le client)
et celui de l'intérieur du programme (les variables)
$_REQUEST fusionne $_GET et $_POST (entre autres) mais ils sont par
essence dans le *même* contexte (celui du web, c'est à dire contenu non
sûr provenant de l'utilisateur), donc leur fusion ne créé pas de problème
supplémentaire de sécurité.

Je considère ceci comme fondamental.



Oui, mais pas pour la raison que vous évoquez.

Les utilisateurs avancé de la
liste savent que de nombreuses applications voyaient leur comportement
détourné en raison du manque de discernement au niveau du tra^itement
des données soumises par le navigateur.



Parce que le simple fait de changer un GET en POST ou le contraire
faisait 'planter' l'application ? Bah alors là le problème est ailleurs
et il me semble qu'on a discuté de cela récemment.

Par exemple OsCommerce,
Wordpress, Dotclear, etc. C'est pourquoi je considère inconcevable qu'on
puisse conseiller l'usage de $_REQUEST à un débutant.



C'est tout à fait concevable et c'est même la bonne façon de faire.
Toutes les bonnes APIs de tous les langages de programmation offrent une
interface identique que l'on soit en GET en POST (tout en étant capable
de discriminer bien sûr quand on en a besoin), ce qui illustre bien que
le problème n'est pas là.
C'est une forme d'abstraction qui, quand on connaît bien les choses (et
quand on ne les connaît pas on s'abstient ou on apprend), est tout à fait
utile.

D'ailleurs, j'espère que $_REQUEST dispara^itra un jour !



C'est le genre de paravent de mesure de sécurité. Supprimer $_REQUEST
n'augmentera en rien la sécurité des applications. Au contraire, un
"faux" sentiment de sécurité est bien pire selon moi que pas de sécurité
du tout, mais clairement avouée.

--
Patrick Mevzek . . . . . . . . . . . . . . Dot and Co
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registrars/prices>
<http://icann-registrars-life.dotandco.net/>
Avatar
Patrick Mevzek
Le Thu, 09 Apr 2009 23:38:55 +0000, Denis Beauregard a écrit:
Si un programmeur était assez tordu pour demander à recevoir deux
données de même nom, l'une dans $_GET et l'autre dans $_POST (ou bien
l'une des deux dans $_COOKIE), alors oui, il aurait probablement besoin
de distinguer par où lui parvient chacune de ces données. Mais dans le
cas d'un programmeur sain d'esprit je ne vois pas ce que ça peut lui
apporter de contrôler ça. Il vaut mieux se concentrer sur les valeurs
reçues !



Pourquoi pas les 3 en parallèle ? get, post et cookie (il y en a un 4e
?).



Comme passage d'informations, il y a le PATH_INFO mais peu utilisé.
Sinon, dans $_REQUEST, il y avait aussi avant $_FILES.
Et question environnement, il y a aussi (mais non fusionné) $_SERVER et
$_ENV

Ceci dit, quand je développe, j'aime bien voir les noms des variables
dans l'URL, histoire de ne pas avoir à cliquer 2 fois quand je
rafraichis une page (avec POST, de mémoire). Donc, cela a du sens de
développer avec une méthode, puis d'utiliser l'autre méthode (sans que



Euh... les deux ne sont pas complétement interchangeables quand même, la
sémantique n'est pas la même.

Je ne comprends pas très bien votre histoire de "voir les variables" ?
En phase de développement, vous ne pouvez pas ajouter des echo dans votre
code pour afficher des informations supplémentaires dans la page
(voir, pour faire plus subtil, des inscriptions javascript qui utilisent
Firebug pour faire du beau debug en console) ?

--
Patrick Mevzek . . . . . . . . . . . . . . Dot and Co
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registrars/prices>
<http://icann-registrars-life.dotandco.net/>
Avatar
Patrick Mevzek
Le Thu, 09 Apr 2009 23:38:55 +0000, Mickael Wolff a écrit:
Si on avais utiliser $_REQUEST, que les données soient soumises en
GET ou en POST n'a pas d'importance. Dans ce cas là, un attaquant
pourrait transmettre un lien forgé à une victime utilisatrice du site :

<http://example.com/?action=news.delete&idB>



... comme il pourrait transmettre un email avec du code HTML et du
javascript qui déclenche l'envoi du formulaire en POST.
Niveau attaque c'est pareil, aucune des deux solutions ne change quoi que
ce soit, preuve que la surface d'exposition est la même et que ce n'est
pas dans ce genre de différences qu'il faut espérer sécuriser
l'application.

Pour qui, au passage, une bonne façon de faire serait de vérifier quelle
est la page "précédente" (et non, pas avec le "referer"), ce qui assure
que la demande de suppression arrive selon le canal prévu, en couplant
avec un mécanisme de jetons uniques pour éviter le rejeu et les liens
directs.

Ce lien peut ^etre explicite (dans un courriel par exemple), ou caché
(et chargé automatiquement) dans une page HTML visitée par l'utilisateur
alors qu'il est connecté à l'application compromise.



Idem en POST.

Moralité, ce n'est pas parce que le programmeur tordu du site a
décidé d'utiliser un nom commun entre les paramètres HTTP (COOKIE
compris) qu'il faut distinguer POST et GET, mais parce qu'un attaquant
peut ^etre tordu et profiter de la na"iveté de chacun pour nuir.



Cela ne s'appelle pas de la naïveté, mais une application mal conçue.
Après tout c'est un métier aussi !
Et cette erreur de conception ne se résout pas en changeant un get en
post ou le contraire en HTML ou un $_GET en $_POST ou le contraire dans
un code PHP.

Je vous conseille à tous la lecture du très bon « Sécurité PHP 5 et
MySQL » qui détaille ce genre de trous de sécurité auquelles on ne peut
que difficilement imaginer.



On ne peut que difficilement imaginer ce genre de trous ? Ah bon ? Mais
là ce n'est pas d'un trou que vous parlez, mais d'un goufre, connu et
archi connu, documenté partout (la preuve vous citez un livre en français
mainstream c'est pas comme s'il fallait se dégoter un PDF en anglais
d'une conférence paumée pour découvrir une nouvelle attaque...).

Après je ne connais pas le livre en question, mais déjà rien que le titre
me fait tiquer :
- il n'existe pas que MySQL, y compris dans/avec PHP. Ca pourrait être
bien de commencer à l'envisager...
- on parle de la sécurité sur le web, en général (et alors les problèmes
sont les mêmes dans tous les langages de programmation et SGBDR), ou de
la sécurité de/en PHP et de/en MySQL ? Ce n'est pas tout à fait la même
chose...

Pour moi *LE* bouquin sur la sécurité pour le web (même si je ne suis pas
d'accord à 100% avec ses recommandations, notamment sur la gestion de la
persistence entre URLs et cookies) c'est le Huseby « Innocent Code ».
Et dedans il n'y a rien de spécifique à PHP ou à MySQL, c'est 100% la
sécurité des environnements web et donc cela s'applique à tout le monde.

--
Patrick Mevzek . . . . . . . . . . . . . . Dot and Co
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registrars/prices>
<http://icann-registrars-life.dotandco.net/>
Avatar
Patrick Mevzek
Le Fri, 10 Apr 2009 00:23:59 +0000, Olivier Miakinen a écrit:
Ahem... c'est tout ? Il n'y a pas un petit id de session quelque part
dans le formulaire ? Mettons par exemple :
<input type='hidden' name='sessid' value='45ef0063d0aab7f39199' />



Encore mieux : un jeton unique, qui est lié à ce formulaire précisément
et cette tentative (telle action sur tel objet). Ainsi, dans la même
"session" (par exemple avec deux onglets simultanés) on peut avoir 2
formulaires distincts (action et/ou objet) qui fonctionneront
correctement sans se marcher l'un sur l'autre.

Cela simplifie pas mal de choses : plus besoin de variables dans le
formulaire et de champ caché, à part le numéro de jeton, car toutes les
données sont stockées sur le serveur, liées au numéro de jeton. Quand on
actionne le bouton, le serveur reçoit le numéro de jeton et retrouve
localement de quelles données il s'agissait, pas besoin de tout
retransmettre.

Je ne connais pas la syntaxe de WGET pour envoyer cette requête, mais si
tu y tiens je veux bien la chercher.



wget --post-data='action=news.delete&idB' ...

Ce lien peut ^etre explicite (dans un courriel par exemple), ou
caché
(et chargé automatiquement) dans une page HTML visitée par
l'utilisateur alors qu'il est connecté à l'application compromise. On
peut cacheer dans une balise img, stype, script, etc. Bien s^ur, le
HTML peut ^etre caché dans le courriel...



Ah, je crois que je comprends enfin où peut être le problème : c'est
quand l'id de session se trouve dans un cookie.



D'où :
1) pourquoi je n'aime pas les cookies comme stockage d'identifiants de
session :-)
2) il faut des jetons par formulaire/action/object, liés à la session
(pour qu'un utilisateur A ne puisse pas utiliser les jetons de
l'utilisateur B), mais sémantiquement séparé.

Oui, en effet dans ce
cas là un lien envoyé par courriel à quelqu'un déjà connecté pourrait
faire ce genre de chose.



Le problème alors n'est pas GET vs POST mais application pas suffisamment
bien concue, c'est à dire qui ne comprend pas comment fonctionne la
gestion des états au-dessus du mécanisme sans états qu'est HTTP (d'accord
personne n'a dit que c'était forcément trivial), et qui n'a pas de modèle
cohérent d'authorisation (que faut-il préciser pour avoir le droit de
supprimer telle information)

--
Patrick Mevzek . . . . . . . . . . . . . . Dot and Co
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registrars/prices>
<http://icann-registrars-life.dotandco.net/>
Avatar
mpg
Mickael Wolff scripsit:

Je pense que par nommage branché tu désigne la distinction des
données soumises en $_POST ou en $_GET.



Je ne sais pas ce que voulait dire Sylvain, mais pour ma part, même si je
perçois plutôt bien la différence technique entre GET et POST (mais peut-être
pas encore toutes les implications que ça a au niveau sécurité, je lis
attentivement ton exemple et ses commentaires à ce sujet), je n'arrive pas à
voir en quoi l'un représente des « données d'alteration » et l'autre « de
consultation ». Peux-tu détailler ce qui se cache derrière ces deux mots ?

Merci,

--
Manuel Pégourié-Gonnard Institut de mathématiques de Jussieu
http://weblog.elzevir.fr/ http://people.math.jussieu.fr/~mpg/
Avatar
Denis Beauregard
Le 10 Apr 2009 07:36:02 GMT, Patrick Mevzek
écrivait dans fr.comp.lang.php:

Le Thu, 09 Apr 2009 23:38:55 +0000, Denis Beauregard a écrit:
Si un programmeur était assez tordu pour demander à recevoir deux
données de même nom, l'une dans $_GET et l'autre dans $_POST (ou bien
l'une des deux dans $_COOKIE), alors oui, il aurait probablement besoin
de distinguer par où lui parvient chacune de ces données. Mais dans le
cas d'un programmeur sain d'esprit je ne vois pas ce que ça peut lui
apporter de contrôler ça. Il vaut mieux se concentrer sur les valeurs
reçues !



Pourquoi pas les 3 en parallèle ? get, post et cookie (il y en a un 4e
?).



Comme passage d'informations, il y a le PATH_INFO mais peu utilisé.
Sinon, dans $_REQUEST, il y avait aussi avant $_FILES.
Et question environnement, il y a aussi (mais non fusionné) $_SERVER et
$_ENV



mais pas réellement un passage d'arguments.

Ceci dit, quand je développe, j'aime bien voir les noms des variables
dans l'URL, histoire de ne pas avoir à cliquer 2 fois quand je
rafraichis une page (avec POST, de mémoire). Donc, cela a du sens de
développer avec une méthode, puis d'utiliser l'autre méthode (sans que



Euh... les deux ne sont pas complétement interchangeables quand même, la
sémantique n'est pas la même.



Je sais. Si je fais un logiciel interrogeant une base de données,
je peux utiliser le GET et le POST en 1re étape (ce que je recherche),
puis le GET dans une liste de choix possibles, donc une série de
details.php?id345.

Durant le développement, si je commence avec un POST, à chaque essai,
le navigateur va me demander si je veux répéter les "POST DATA", alors
qu'avec un GET, les arguments étant dans l'URL, la question n'est pas
pertinente.

Par la suite, cela dépend si les données sont sensibles ou pas. Si
j'ai un GET, la chaîne recherchée par l'utilisateur sera visible dans
l'historique et donc un utilisateur plutôt novice utilisant la base
dans une bibliothèque publique pourrait laisser des traces. Imaginez
par exemple une recherche dans une base de données personnelles ou
mieux, le mot de passe dans l'URL.

Je permets donc les deux, soit de passer par le GET (j'envoie l'URL
pour se connecter avec le mot de passe) et l'utilisateur ajoute le
lien à ses signets à la maison, et de passer par le POST (il y a
des champs pour le nom d'usager et le mot de passe dans la page
d'accueil, mais ces données ne sont pas dans l'URL) pour l'utilisateur
qui travaillerait depuis un ordinateur public.


Je ne comprends pas très bien votre histoire de "voir les variables" ?
En phase de développement, vous ne pouvez pas ajouter des echo dans votre
code pour afficher des informations supplémentaires dans la page
(voir, pour faire plus subtil, des inscriptions javascript qui utilisent
Firebug pour faire du beau debug en console) ?



Avec le GET et donc l'URL, je peux modifier facilement l'URL pour
changer l'argument et faire le test sans remonter d'une page.
Et j'ajoute quelques echo mais pour d'autres raisons.


Denis
Avatar
Paul
mpg a écrit :
Mickael Wolff scripsit:

Je pense que par nommage branché tu désigne la distinction des
données soumises en $_POST ou en $_GET.



Je ne sais pas ce que voulait dire Sylvain, mais pour ma part, même si je
perçois plutôt bien la différence technique entre GET et POST (mais peut-être
pas encore toutes les implications que ça a au niveau sécurité, je lis
attentivement ton exemple et ses commentaires à ce sujet), je n'arrive pas à
voir en quoi l'un représente des « données d'alteration » et l'autre « de
consultation ». Peux-tu détailler ce qui se cache derrière ces deux mots


Bien sûr, qu'il peut, et peut être même va t il le faire.... Mais pour
dire quoi ? qu'il s'agit d'une pratique sodomite des hyménoptéres courants ?



Avatar
Patrick Mevzek
Le Fri, 10 Apr 2009 13:51:23 +0000, Denis Beauregard a écrit:
Par la suite, cela dépend si les données sont sensibles ou pas. Si j'ai
un GET, la chaîne recherchée par l'utilisateur sera visible dans
l'historique et donc un utilisateur plutôt novice utilisant la base dans
une bibliothèque publique pourrait laisser des traces. Imaginez par
exemple une recherche dans une base de données personnelles ou mieux, le
mot de passe dans l'URL.



Dans ce cas l'application est mal conçue, que ce soit un GET ou un POST
n'y change rien (pensez à un sniffeur sur le réseau...), un mot de passe
n'a pas à circuler en clair.

Avec le GET et donc l'URL, je peux modifier facilement l'URL pour
changer l'argument et faire le test sans remonter d'une page.



Une extension comme Firebug fait des merveilles dans tous les cas pour ce
genre de choses...

--
Patrick Mevzek . . . . . . . . . . . . . . Dot and Co
<http://www.dotandco.net/> <http://www.dotandco.com/>
<http://www.dotandco.net/ressources/icann_registrars/prices>
<http://icann-registrars-life.dotandco.net/>
Avatar
Mickael Wolff
Patrick Mevzek a écrit :

Le problème du register_global est de fusionner deux contextes qui n'ont
rien à voir : celui de l'environnement Web (les échanges avec le client)
et celui de l'intérieur du programme (les variables)



Le jet des variables HTTP dans le scope global n'était pas le
problème. Personnelement, hormis dans les script simples
d'apprentissage, je ne vois pas comment on peut sérieusement utiliser
les variables globales dans ces fonctions. Dans les cursus de formation
des développeurs, les variables globales sont toujours présentées comme
l'une des plaies de la programmation, au côté de goto.


$_REQUEST fusionne $_GET et $_POST (entre autres) mais ils sont par
essence dans le *même* contexte (celui du web, c'est à dire contenu non
sûr provenant de l'utilisateur), donc leur fusion ne créé pas de problème
supplémentaire de sécurité.



Je pars du principe qu'aucune donnée n'est fiable. Quelle que soit ça
provenance, même si les données provenant de sources considérées comme
sûres doivent être considérées comme compromises :D Mais c'est un point
de vu paranoïaque.

Maintenant je regrète : les contextes POST, GET et COOKIE sont
différents. Qu'ils proviennent de la même source ne permettent pas de
les considérer comme équivalent. Pourtant tu devrais le savoir, tu n'es
pas un abruti, mais je pense que tu n'as jamais observé la gueule d'une
requête. Si ces trois contextes étaient interchangeables, pourquoi
sont-ils séparés, et pourquoi leur sémantique (et donc leur
comportement) est-il si différent ?

Oui, mais pas pour la raison que vous évoquez.



J'évoque deux raisons. La sémantique et la sécurité. Elles sont
liées, certes, mais importantes.

Parce que le simple fait de changer un GET en POST ou le contraire
faisait 'planter' l'application ? Bah alors là le problème est ailleurs
et il me semble qu'on a discuté de cela récemment.



Mais alors où est-il ? Si on ne peut plus distinguer les données
saisies en POST et en GET ? Alors certes, pour vérifier que j'ai reçu
une requête POST je vérifie la clé 'REQUEST_METHOD' de la superglobale
$_SERVER, mais j'utilises tout de même $_POST et $_GET pour distinguer
la provenance des instructions. Simplement parce qu'une application
complexe peut requérir l'accès à une ressource ne même temps que la
modification d'une autre. Mais aussi parce que l'ordre d'importation des
contextes est configurable, il n'y a aucune garantie de fonctionnement
alors.

En fait, avant d'utiliser $_REQUEST, tu vérifie la valeur de la
variable $_SERVER['REQUEST_METHOD'] ? Et finalement, lorsque tu es en
'POST' tu ignores les paramètres GET (donc en partie l'URL) ?

Par exemple OsCommerce,
Wordpress, Dotclear, etc. C'est pourquoi je considère inconcevable qu'on
puisse conseiller l'usage de $_REQUEST à un débutant.



C'est tout à fait concevable et c'est même la bonne façon de faire.
Toutes les bonnes APIs de tous les langages de programmation offrent une
interface identique que l'on soit en GET en POST (tout en étant capable
de discriminer bien sûr quand on en a besoin), ce qui illustre bien que
le problème n'est pas là.



Tu as des noms d'API ? Ça m'intéresse en C++ ;)

D'ailleurs, j'espère que $_REQUEST dispara^itra un jour !



C'est le genre de paravent de mesure de sécurité. Supprimer $_REQUEST
n'augmentera en rien la sécurité des applications. Au contraire, un
"faux" sentiment de sécurité est bien pire selon moi que pas de sécurité
du tout, mais clairement avouée.



C'est vrai que de supprimer register_global est un paravent ;)

--
Mickaël Wolff aka Lupus Michaelis
http://lupusmic.org
1 2 3 4 5