Page 1 of 1

Sécurisation de mon code - Demande de conseil

PostPosted: Wed Aug 04, 2010 1:20 pm
by GOLGOTA
Salut :)

Comme dit dans ma présentation, j'ai commencer le développement de mon site. Je commencerais par un blog car c'est rapide à coder 2 petites pages php. J'avais déjà bien bosser sur un site entier auparavant, mais vu la taille du truc et mon immense désire d'aller le plus vite possible, j'ai été vite dégouter car trop d'erreur, beaucoup de failles de sécurité, etc..
Donc là, j'irais étape par étapes, tranquillement, bref !!

Voici le code. Pour information, je dois encore inclure un script anti-bot pour protégé le formulaire de post de commentaire. Et je n'ai protégé la page admin qu'avec un fichier .htaccess, il n'y donc pas encore de script pour enregistrer un admin ou des membres.

Index.php

[code:1:98697cb745]
<?php
//Inclusion du fichier config, nécéssaire pour la connexion à la base de données
include "include/config.php";

//On récupère a, qui est la variable qui nous guidera dans les conditions
if(empty($_GET['a']))
{
$a = NULL;
}
else
{
$a = htmlspecialchars($_GET['a']);
}

if($a == 1)
{
//Si a = 1, c'est qu'on veut afficher un article et ses commentaires
//1. On charge l'article, en ayant pris soin de récupéré son id.
$id = htmlspecialchars($_GET['id']);
$requete = $bdd->prepare('SELECT * FROM article WHERE id = :id');
$requete->execute(array('id' => $id));
$donnees = $requete->fetch();

$titre = htmlspecialchars($donnees['titre']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));

echo "<fieldset>";
echo "<label>Titre : ". $titre ."</label><br />";
echo "<p>". $contenu ."</p>" ;
echo "</fieldset>";

$requete->closeCursor();

//2. On récupère les commentaires lié à l'id de l'article précédemment charger.
$requetes = $bdd->prepare('SELECT * FROM commentaire WHERE id_article = :id');
$requetes->execute(array('id' => $id));

while ($donnees = $requetes->fetch())
{
$auteur = htmlspecialchars($donnees['auteur']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));
echo "<fieldset>";
echo "<p><label>". $auteur ." à dit :</label></p>";
echo "<p>". $contenu ."</p>";
echo "</fieldset>";
}
$requetes->closeCursor();

}
if($a == 2)
{
//Si a = 2, c'est qu'on veut poster un nouveau commentaire, on affiche alors un formulaire.
//L'id est transféré au formulaire et on le retransferera directement au traitement des donnnées
//pour lié le commentaire à l'article dans la base de données avec le champ id_article.
$id = htmlspecialchars($_GET['id']);
echo "<form action=\"index.php?a=3&id=". $id ."\" method=\"POST\" />";
?>
<fieldset>
<label>Poster un commentaire :</label><br />
Auteur : <input type="text" name="auteur" /><br />
Contenu :<br />
<textarea name="contenu" id="contenu" row="20" cols="50"></textarea><br />
<input type="submit" value="Poster" />
</fieldset>
</form>
<?
}
if($a == 3)
{
//Si a = 3, on traîte les données reçues.
$id = htmlspecialchars($_GET['id']);
$auteur = htmlspecialchars($_POST['auteur']);
$contenu = htmlspecialchars($_POST['contenu']);

$requete = $bdd->prepare('INSERT INTO commentaire (auteur, contenu, id_article) VALUES (:auteur, :contenu, :id_article) ');
$requete->execute(array(
'auteur' => $auteur,
'contenu' => $contenu,
'id_article' => $id));

echo "Pour revenir sur le message : <a href=\"index.php?a=1&id=". $id ."\">Cliquez ici</a><br />";
echo "Pour revenir sur la page principale : <a href=\"index.php\">Cliquez ici</a><br />";
}
if($a == NULL)
{
//Si a n'a pas de valeur, alors on charge les articles.
$requete = $bdd->query('SELECT * FROM article ORDER BY id DESC Limit 0,50');

while ($donnees = $requete->fetch())
{
$id = htmlspecialchars($donnees['id']);
$titre = htmlspecialchars($donnees['titre']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));

echo "<fieldset>";
echo "<label>Titre : ". $titre ."</label><br />";
echo "<p>". $contenu ."</p>" ;
echo "<a href=\"index.php?a=1&id=". $id ."\">Voir les commentaires</a></br>";
echo "<a href=\"index.php?a=2&id=".$id ."\">Ajouter un commentaire</a><br />";
echo "</fieldset>";
}
$requete->closeCursor();
}
?>
[/code:1:98697cb745]

La page admin.php

[code:1:98697cb745]
<?php

include "../include/config.php";
if(empty($_GET['a']))
{
$a = NULL;
}
else
{
$a = htmlspecialchars($_GET['a']);
}
if(empty($_GET['i']))
{
$i = NULL;
}
else
{
$i = htmlspecialchars($_GET['i']);
}
switch ($a)
{
//Poster un article
case 1:
?>
<form action="admin.php?a=3&i=1" method="POST">
<fieldset>
<label>Poster un article</label><br />
Le Titre : <input type="text" name="titre" id="titre" /><br />
Le contenu :<br />
<textarea name="contenu" id="contenu" row="20" cols="50"></textarea><br />
<input type="submit" value="Poster" /><br />
</fieldset>
</form>
<?
break;

//Modifier un article
case 2:
$id = htmlspecialchars($_GET['id']);

$requete = $bdd->prepare('SELECT titre, contenu FROM article WHERE id = :id');
$requete->execute(array('id' => $id));
$donnees = $requete->fetch();

$titre = htmlspecialchars($donnees['titre']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));

echo "<form action=\"admin.php?a=3&i=2&id=". $id ."\" method=\"POST\">";
echo "<fieldset>";
echo "<label>Modifier un article</label><br />";
echo "Le Titre <input type=\"text\" name=\"titre\" value=\"". $titre ."\" /><br />";
echo "Le Contenu :<br />";
echo "<textarea name=\"contenu\" id=\"contenu\" row=\"20\" cols=\"50\">". $contenu ."</textarea><br />";
echo "<input type=\"submit\" value=\"Modifier\" /><br />";
echo "</fieldset>";
echo "</form>";

$requete->closeCursor();
break;

//Traitement des données des articles ajout/modification/suppression
case 3:
if($i == 1)
{
//On post un article
$titre = htmlspecialchars($_POST['titre']);
$contenu = htmlspecialchars($_POST['contenu']);

$requete = $bdd->prepare('INSERT INTO article (titre, contenu) VALUES(?, ?)');
$requete->execute(array($_POST['titre'], $_POST['contenu']));
echo "Article ajouté ! <a href=\"admin.php\">Cliquez ici</a> pour revenir à la page principale";
$requete->closeCursor();
}
if($i == 2)
{
//On modifie un article
$id = htmlspecialchars($_GET['id']);
$titre = htmlspecialchars($_POST['titre']);
$contenu = htmlspecialchars($_POST['contenu']);

$requete = $bdd->prepare('UPDATE article SET titre = :titre, contenu = :contenu WHERE id = :id ');
$requete->execute(array(
'titre' => $titre,
'contenu' => $contenu,
'id' => $id));
echo "Article modifié !<a href=\"admin.php\">Cliquez ici</a> pour revenir à la page principale.";
$requete->closeCursor();
}
if($i == 3)
{
//On supprime un article et ses commentaires.
//1. On supprime les commentaires lié à l'article.
$id = htmlspecialchars($_GET['id']);
$requete = $bdd->prepare('DELETE FROM commentaire WHERE id_article = :id');
$requete->execute(array('id' => $id));
//2. On supprime l'article.
$requete = $bdd->prepare('DELETE FROM article WHERE id = :id');
$requete->execute(array('id' => $id));
echo "L'article et ses commentaires ont bien été supprimés ! <a href=\"admin.php\">Cliquez ici</a> pour revenir à la page principale.";
$requete->closeCursor();
}
else
{
echo "Vous n'avez rien à faire ici.";
}
break;

//Lister les articles
case 4:
$requete = $bdd->query('SELECT id, titre FROM article ORDER BY id DESC');

echo "<table>";
while ($donnees = $requete->fetch())
{
$id = htmlspecialchars($donnees['id']);
$titre = htmlspecialchars($donnees['titre']);
echo "<tr><td>". $id ."</td>
<td>". $titre ."</td>
<td><a href=\"admin.php?a=3&i=3&id=". $id ."\">Supprimer</a></td>
<td><a href=\"admin.php?a=2&id=". $id ."\">Modifier</a></td>
<td><a href=\"admin.php?a=5&id=". $id ."\">Moderer</a></td></tr>";
}
echo "</table>";
$requete->closeCursor();
break;

//Voir un article et ses commentaires
case 5:
$id = htmlspecialchars($_GET['id']);
$requete = $bdd->prepare('SELECT titre, contenu FROM article WHERE id = :id ');
$requete->execute(array('id' => $id));
$donnees = $requete->fetch();

$titre = htmlspecialchars($donnees['titre']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));

echo "<fieldset>";
echo "<label>". $titre ."</label><br />";
echo "<p>". $contenu ."</p>" ;
echo "<fieldset />";

$requete = $bdd->prepare('SELECT id, auteur, contenu FROM commentaire WHERE id_article = :id');
$requete->execute(array('id' => $id));

while($donnees = $requete->fetch())
{
$idc = $donnees['id'];
$auteur = htmlspecialchars($donnees['auteur']);
$contenu = nl2br(htmlspecialchars($donnees['contenu']));
echo "<fieldset>";
echo "<label>". $auteur ." a dit :</label><br />";
echo "<p>". $contenu ."</p>";
echo "<a href=\"admin.php?a=6&id=". $idc ."\">Supprimer le commentaire ?</a>";
echo "</fieldset>";
}
$requete->closeCursor();
break;

//Supprimer un commentaire
case 6:
$id = htmlspecialchars($_GET['id']);
$requete = $bdd->prepare('DELETE FROM commentaire WHERE id = :id');
$requete->execute(array('id' => $id));

echo "Le commentaire à été supprimer.<br />";
echo "<a href=\"admin.php\">Cliquez ici</a> pour retourner au menu de départ";
$requete->closeCursor();
break;

//Aucun choix n'est fait, on affiche la page d'accueil d'admin
default:
echo "Que voulez-vous faire ?<br />";
echo "<a href=\"admin.php?a=1\">Poster un nouvel article ?</a><br />";
echo "<a href=\"admin.php?a=4\">Voir la liste des articles ?</a><br />";
echo "<a href=\"../index.php\">Retourner sur le blog ?</a><br />";
break;
}
?>
[/code:1:98697cb745]

Et la page config.php ne contenant qu'une seule ligne :

[code:1:98697cb745]
$bdd = new PDO('mysql:host=localhost;dbname=nom_bdd', 'pseudo', 'mot_de_passe_db');
[/code:1:98697cb745]

Voilà, ce que je cherche c'est des conseils, ou mieux une analyse du code qui me dirait là ou je fais des erreurs, autant pour la sécurité que pour faciliter l'utilisation du script.

J'espère ne pas en demander de trop :oops:

Merci d'avance pour vos conseils, votre aide,

Golgota

PostPosted: Wed Aug 04, 2010 8:14 pm
by Manu404
Je te conseil de lire des cours sur l'architecture en php. Le mieux est de premièrement developper une série de classe que tu utilisera pour faire tes request. Ces classes contiennent des classes de connection, configuration, création des user utilisé dans les connections, gestion des droits. ensuite ton fichier de config contient lui des var pour presque "tout". Ca va de l'ip du srv SQL au nom des tables. Tente d'utiliser des design patterns pour résoudre le plus de situation possible avec de modèles éprouvés.

PostPosted: Thu Aug 05, 2010 10:58 am
by GOLGOTA
J'ai fait des recherches et j'commence à comprendre ce que tu me dis :)

L'utilisation des class à l'air vraiment pas mal, ça évite de ré-écrire plein de chose déjà tapées.

Merci, j'vais approfondir tout ça :)

PostPosted: Thu Aug 05, 2010 11:33 am
by JREM
Salut, je voulais rajouter qu'on utilise "mysql_real_escape_string" pour protéger ses requêtes de l'injection sql.

PostPosted: Thu Aug 05, 2010 12:38 pm
by GOLGOTA
Ha ! Merci :)

Je vais corriger ça :D