Bonjour Pytet,
Je te remercie pour ton message détaillé.
J'ai parcouru toute la doc que tu as listé.
J'ai toujours eu un peu de mal avec la doc PHP pour être honnête.
Pour être certain de bien avoir compris, je me permets de reformuler les choses à base d'un fil rouge (et de questions complémentaires).
En cas d'erreur de compréhension, me dire l'étape où je me suis planté svp 
Je sais que mon message est un peu long mais la validation des étapes ci-dessous (ou leur invalidation) me permet de comprendre ce que je fais de bien ou de continuer à creuser ou je ne suis pas encore au clair.
D'avance un grand merci pour l'aide qui sera apportée 
PROTECTION CONTRE INJECTION SQL/XSS :
1 - Connexion conforme à la BDD de type :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<?php
// Connexion à la base de données
try
{
$acces_bdd = new PDO('mysql:host=localhost;dbname=nomdeladb;charset=utf8', 'utilisateur','mdp',
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION) );
}
catch (Exception $e)
{
die('Erreur : ' . $e->getMessage());
}
?> |
Question :
En parcourant la doc que tu as envoyé et certains liens dans cette même doc, il est conseillé que la connexion à la base de données ne devrait pas se faire avec le profil 'admin' ou 'superUtilisateur'.
L'utilisateur communiqué par défaut par le service d'hébergement est par défaut un 'superUtilisateur' de la BDD.
Comment faire pour créer un profil utilisateur lamba (et comment mettre des restrictions) au travers duquel on se connectera à la BDD ?
2 - Nous recevons des données de la part de $_GET ou $_POST que nous devons inscrire dans une table de la BDD
Cas typique d'un formulaire d'inscription par exemple :
a - Utilisation des filtres pour obtenir le type de données que l'on souhaite
Je me suis amusé à tester sur une page créée à cet effet :
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
|
<html>
<h1>TESTS</h1>
<h2>Formulaire de test</h2>
<form action="index.php" method="post">
<label>Ma chaine de caractère :</label>
<input type="text" name="user_name"/></br>
<input type="submit" value="Envoyer"/>
</form>
<h2>Résultat :</h2>
<?php
if(!isset($_POST['user_name']))
{
echo "Acune donnée entrée";
}
else
{
if(is_numeric($_POST['user_name'])) // Cas de la popup => passer is_numeric en is_string
{
$message=($_POST['user_name']);
//$message=htmlspecialchars($message); //Cas de la popup => Seule cette ligne permettra de désactiver l'affichage de la popup
echo $message;
}
else
{
echo "On accepte pas cela"; // Si on passe en is_string, le else ne sert à rien vu que tout sera interprété comme une chaine de caractère...
}
}
?>
</html> |
is_string =>peu importe ce que l'on place dans un champs de type input="text", il validera tout comme étant du texte : j'ai un peu de mal à voir son utilité du coup.
is_numeric => il fait bien la différence entre du texte et des chiffres
...
Bien compris pour la vérification du type en étape 1 a partir de la récupération de données
Bien compris pour la vérification de valeur en étape 2.
Et si j'ai bien tout compris... ce genre de texte (popup) tapé dans un input :
<script>alert("YOUPI");</script>
ne pourra jamais être traité avec le couple type/valeur à partir du moment où l'attend de l'utilisateur qu'il :
. Donne un pseudo
. Donne un avis ...
Du coup, si on souhaite afficher le message de cet utilisateur (par exemple avant validation), la on utilise
1 2 3
|
$message=($_POST['user_name']);
$message=htmlspecialchars($message); |
Pour désactiver le fonctionnement du code depuis notre page web
Si le client a placé :
<script>alert("YOUPI");</script>
Il lira sur son écran : <script>alert("YOUPI");</script> (code désactivé => faille XSS comblée).
En revanche si le client décide d'enregistrer son commentaire (insertion ou mise à jour), le commentaire part en étape 3 vers la table
3 - INSERTION - MAJ dans une table de la BDD => requêtes préparées :
Nous attendons un texte et nous recevons ceci :
<script>alert("YOUPI");</script>
Ou un code plus méchant visant à attaquer la BDD
$message = "Code plus méchant provenant de $_POST ou $_GET";
Les données contenues dans $message et potentiellement problématiques pour la sécurité de la BDD seront automatiquement rendues inoffensive (la majorité si j'ai bien lues) par le serveur
qui va traiter la demande si on utilise des requêtes préparées.
Si je suis les informations que tu m'as communiqué,
Mon exemple pour INSERER
1 2 3 4 5 6
| //Cas INSERT INTO
$rep=$acces_bdd->prepare('INSERT INTO maTAble ($recuperation_get, $recuperation_post) VALUES(:$recuperation_get, :$recuperation_post);
$rep->execute(array(
'Colonne01' => $recuperation_get,
'Colonne02' => $recuperation_post
)); |
N'est pas tout à fait correct et sécurisé c'est cela ?
Il devrait avoir la forme suivante :
1 2 3 4 5 6 7 8
| //Cas INSERT INTO
$rep=$acces_bdd->prepare('INSERT INTO maTAble ($recuperation_get, $recuperation_post) VALUES(:$recuperation_get, :$recuperation_post);
$rep->bindPram(':$recuperation_get', $recuperation_get)
$rep->bindPram(':$recuperation_post', $recuperation_post)
$recuperation_get = $_GET[''];
$recuperation_post = $_POST[''];
$rep-> execute(); |
Ou alors ces deux code d'insertion sont tous les deux sécurisés mais le dernier code (celui avec bindParam) permet juste de pouvoir insérer plusieurs lignes en changeant simplement la dernière partie :
1 2 3
| $recuperation_get = $_GET[''];
$recuperation_post = $_POST[''];
$rep-> execute(); |
Auquel cas si on a qu'une seule ligne ou peut se servir de l'un ou de l'autre, si plusieurs lignes a créer, on passe sur le second avec bindParam.
Est ce bien cela ?
Pour le cas de l'UPDATE j'aurai ainsi la transformation suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| //Cas UPDATE
$rep=$acces_bdd->prepare('UPDATE maTAble SET $recuperation_get =:$recuperation_get, $recuperation_post =:$recuperation_post WHERE id=:id');
$rep->execute(array(
'Colonne01' => $recuperation_get,
'Colonne02' => $recuperation_post,
'id' => $Ma_Recherche['id']
));
// deviendrait alors
$rep=$acces_bdd->prepare('UPDATE maTAble SET $recuperation_get =:$recuperation_get, $recuperation_post =:$recuperation_post WHERE id=:id');
$rep->bindPram(':$recuperation_get', $recuperation_get)
$rep->bindPram(':$recuperation_post', $recuperation_post)
$recuperation_get = $_GET[''];
$recuperation_post = $_POST[''];
$rep-> execute();
));
// C'est bien cela ? |
4 - Si ma compréhension du point 3 est correcte, alors les requêtes préparées vont permettre à elles seules de stopper la majorité des attaques par injection SQL.
Y-at-il des choses supplémentaires à réaliser ?
Ou la phrase "la majorité des attaques" est juste placée dans la documentation car on veut juste dire qu'aucune protection n'est certaine a 100% et viendra un jour ou elle sera franchie... et ou il faudra rajouter une couche de protection 
Merci d'avance pour vos retours afin d'être certain d'avoir compris et d'appliquer les bonnes pratiques.
Partager