« MySQL/Sécurité » : différence entre les versions

Un livre de Wikilivres.
Contenu supprimé Contenu ajouté
m →‎Paramètres de connexion : censé = supposé, sensé = qui a du (bon) sens.
Ligne 64 : Ligne 64 :
Il est donc fortement déconseillé d'envoyer ce genre de commandes :
Il est donc fortement déconseillé d'envoyer ce genre de commandes :
<source lang=sql>
<source lang=sql>
SELECT 1 FROM `users` WHERE `password`=MD5('abraxas')
SELECT 1 FROM `clients` WHERE `password`=MD5('abraxas')
</source>
</source>


Préférer depuis un .php par exemple :
Préférer depuis un .php par exemple :
<source lang=php>
<source lang=php>
$sql = "SELECT 1 FROM `users` WHERE `password`=MD5('".md5('abraxas')."')";
$sql = "SELECT 1 FROM `clients` WHERE `password`=MD5('".md5('abraxas')."')";
</source>
</source>



Version du 13 décembre 2019 à 17:48

Sécurité

Sur Internet, des pirates tentent de récupérer des données en violant leurs accès. Ils insèrent souvent du code dans une page HTML ou PHP, par injection de code, généralement par[1] :

  • le biais d'un formulaire HTML qui permet d'entrer des données dans la base de données
  • ou alors en insérant des données par le biais de la barre d'adresse de la fenêtre,
  • par le dépôt d'un fichier sur le serveur (upload)
  • ou toute autre voie d'accès au serveur possible.

Les bases de données permettent d'assurer le stockage des informations en liaison par exemple avec des pages HTML couplées avec PHP. Donc tout le monde peut en avoir accès par l'intermédiaire d'un client relié au serveur. MySQL basé sur SQL est notamment très utilisé avec PHP. Il est donc pertinent d'examiner quelques notions de sécurité en matière de SQL.

En ce qui concerne SQL, il faut savoir premièrement qu'une astuce de programmation ou un détournement de requête possible à partir d'un serveur a de bonnes chances de réussir sur un autre et il en est de même avec les applications web mêmes, qui peuvent être utilisées afin d'atteindre le serveur et d'en saccager les données.


Paramètres de connexion

Parfois, les paramètres de connexion (dont login et mot de passe) sont stockés dans un fichier texte non crypté, comme un .ini. Cela n'est donc pas recommandé : si un utilisateur devine son nom il peut le lire sans peine. S'il est situé en dehors du répertoire WWW c'est mieux, mais la meilleure façon est de les enregistrer dans un programme (ex : .php).

Il est toujours possible pour un utilisateur de trouver les accès FTP, donc il vaut mieux en utiliser d'autres pour MySQL.

Inutile de se souvenir des mots de passe MySQL car le programme est censé le retrouver automatiquement. Il convient donc d'en choisir un robuste : très long, avec au moins une majuscule, une minuscule, un symbole (ex : '_') et un chiffre. Le tout sans contenir de mots du dictionnaire car ils sont utilisés pour accélérer les crackages lors d'attaque par force brute.

Logo

Ne jamais les stocker autre part, y compris dans des e-mails.

Injections SQL

Définition

Normalement les valeurs stockées dans $_POST peuvent être insérées directement dans des requêtes SQL. Toutefois les injections SQL exploitent une faille de sécurité engendrée par le caractère d’échappement.

Exemple

Si on s'attend à recevoir un nombre (ex : 42), et qu'en fait $_POST contient une chaine avec échappement ("'42' OR 1") cela change complètement son résultat :

 DELETE FROM `articles` WHERE `id`=42       -- supprime une ligne
 DELETE FROM `articles` WHERE `id`=42 OR 1  -- supprime toutes les lignes (car 1 est toujours vrai)

L'utilisateur peut aussi insérer des commandes plus complexes séparées par des points-virgules :

 SELECT * FROM `table1` WHERE title='bla bla'                           -- sélectionne
 SELECT * FROM `table1` WHERE title='bla bla'; TRUNCATE TABLE `table1`  -- supprime tout

Par ailleurs, si un utilisateur découvre comment manipuler une base de cette façon, il peut très bien se créer un compte administrateur ensuite, et effectuer des modifications discrètes dans le but de récupérer de l'argent (fausses factures, phishing...).

Solution

Il faut vérifier que la variable stocke bien le type de données prévu :

  • Pour les chaines de caractères : comme elles sont entourées d'apostrophes, tous ceux qu'elles contiennent doivent être convertis (ex : en '' ou \'). Par exemple, PHP propose mysql_real_escape_string pour gérer ces substitutions.
  • Pour les dates : les entourer d'apostrophes comme les chaines.
  • Pour les noms SQL (tables, champs...) : les entourer d'apostrophes comme les chaines.
  • Pour les nombres : s'ils contiennent autre chose que des chiffres, ils ne conviennent pas.
  • NULL / UNKNOWN / TRUE / FALSE : ne doivent jamais être rentrées par l'utilisateur.

Par ailleurs, aucun commentaire SQL ne devrait pourvoir être inséré par l'utilisateur.

Mots de passe

Généralement ils sont cryptés puis dans la base par les applications. Par contre si c'est fait en SQL, c'est qu'ils ont été écrits au moins une fois en clair et donc étés visibles :

  • Dans les logs du serveur.
  • Dans les logs MySQL.
  • Dans SHOW PROCESSLIST.

Il est donc fortement déconseillé d'envoyer ce genre de commandes :

 SELECT 1 FROM `clients` WHERE `password`=MD5('abraxas')

Préférer depuis un .php par exemple :

 $sql = "SELECT 1 FROM `clients` WHERE `password`=MD5('".md5('abraxas')."')";
  • Ne jamais utiliser de fonctions de cryptage non sécurisées, comme PASSWORD().
  • Ni de cryptage réversible (se contenter de comparer si un chaine cryptée est égale à une autre chaine cryptée comme authentification). Ou bien les mots de passe stockées dans une base doivent être impossibles à sélectionner (avec SELECT).
  • Seulement du hachage cryptographique, comme SHA256, pas d'algorithmes plus vieux comme MD5.

SSL

Si le contenu de la base est publique, il n'y a pas de raison de crypter les communications.

Toutefois il peut y avoir un accès restreint pour les droits d'écriture, ce qui nécessite des mots de passe.

Le cryptage SSL s'avère une bonne solution pour cela. En effet, en plus de crypter les messages, il certifie que l'utilisateur est bien celui qui était prévu (même si ce dernier a donné son mot de passe par phishing).

Risques dans les manipulations de données

On en retrouve plusieurs types :

  • Contournement d'une clause where, c'est-à-dire neutraliser la clause WHERE en injectant une condition constante (toujours vraie ou toujours fausse, comme par exemple : SELECT * FROM table WHERE 1;
  • Modification sans limite, comme par exemple la destruction totale de données avec la commande DELETE : DELETE FROM table WHERE 1;
  • Insertions indésirables, où le pirate peut injecter une ligne complète qui sera traitée à son insu par la base de données. L'application insère ainsi des valeurs dont elle n'est plus maîtresse, par exemple le pirate peut injecter : md5('secret') sans un formulaire, ce qui revient à crypter le mot 'secret', que la base de données ne pourra plus retrouver ou traiter.
  • Exécutions multiples : par exemple une injection pour placer une requête dans une autre requête initiale, afin d'exécuter toutes les injections que veut le pirate.
  • Surcharger le serveur : c'est-à-dire modifier une requête afin qu'elle engendre une charge de travail importante et inutile pour le serveur.
  • Exportations cachées : en exportant des données, en les extrayant de leur dépôt habituel et les placer par la suite dans un réceptacle public plus facile à lire. Cela ce fait par exemple en contournant la clause WHERE, ou alors en insérant des fichier externes directement sur le serveur SQL.

Chiffrement d'un mot de passe

Le chiffrement d'un mot de passe ou d'une donnée consiste en sa transformation en une autre donnée par le biais d'une méthode extrêmement difficile à inverser voire impossible avec les fonctions de hachage. MySQL offre des méthodes de chiffrement des données et par la même du mot de passe. Nous avons par exemple :

INSERT INTO utilisateurs(identifiant, motdepasse) VALUES ('$id', MD5('$mdp'));

Vérification : SELECT id FROM utilisateurs WHERE identifiant = '$idTest' AND motdepasse = MD5('$mdpTest');

Pour du contenu sécurisé à afficher : Stockage : INSERT INTO dossiersSecrets(titre, contenu) VALUES ('$titre', AES_ENCRYPT('$contenu','motdepasse'));

Récupération : SELECT titre, AES_DECRYPT(contenu,'motdepasse') AS contenu FROM dossiersSecrets;

Sécurité PHP

Voici quelques types d'attaques que l'on retrouve fréquemment :

  • l'injection de code distant.

Par exemple, c'est introduire une instruction PHP dans une page, qui ira chercher du code PHP sur un site distant pour le ramener sur le serveur local du pirate et l'exécuter comme code local, afin de prendre contrôle du serveur et des données du serveur distant piraté.

  • l'exécution du code à la volée.

Cela ce fait par exemple à l'aide de : eval(), fonction qui prend en argument une chaîne de caractère pour l'exécuter comme du code PHP ; et par là exécuter des opérations destructrices de données par cette voie.

  • le téléchargement de fichiers ; ce qui permet d'importer du code PHP sur un site.

Il suffit en effet que ce site ait des autorisations de lecture et qu'il soit accessible depuis le Web, sans besoin de droit d'exécution ou d'écriture pour exécuter tous les codes PHP que veut le pirate. En stockant le fichier, par la fonction "upload" (ex. image), le code est exécuté sur le serveur pirater et vient en saboter ou déranger le fonctionnement et même la lecture des autres documents.

  • La directive register_globals;

Si elle est activée permet d'injecter dans les scripts toutes sortes de variables ; ce qui rend la programmation de script peu sûr. Heureusement que dans les versions supérieures à PHP 4.2 l'option register_globals est désactivée par défaut.

  • filtrage des données ;

C'est-à-dire la gestion des erreurs, ou les mécanismes par lesquels l'application web déterminera la validité des données qui entrent et sortent de l'application. Il s'agit donc de s'assurer que : permièrement on ne puisse pas contourné le filtrage des données, que deuxièmement les données invalides ne puissent pas être confondues avec des données valides et enfin identifier l'origine des données.

Vous trouverez les solutions possibles à ces problèmes dans ce guide de sécurité PHP en ligne : http://phpsec.org/.

La solution des systèmes de gestion de contenu ou de création de site web

Une autre solution est d'utiliser des systèmes de création et de gestion de contenu Web, pour créer un site web personnel et l'agrémenter d'une petite bases de données. L'avantage ici est que si vous utilisez par exemple une application comme http://sites.google.com/.


L'avantage est que la sécurité est ici gérée par de grandes sociétés comme ici 'Google' qui engage des experts en la matière. Il devient dès lors très difficile pour des pirates de saccager les données de l'application web que vous créez, ainsi que la base de données.

Sites.google, par exemple, est une application en ligne qui permet le plus simplement possible de créer un petit site Internet perso agrémenter d'une base données. Pas besoin ici de sécuriser les données c'est la société Google, qui s'en charge ! Par exemple, Google.site permet de rassembler rapidement en un seul endroit une série d'informations, tout en sécurité :

  • vidéos
  • agendas,
  • présentations,
  • informations stockées dans une base de données,
  • pièces jointes,
  • texte.

Elle permet également en matière de sécurité d'autoriser leur accès ou leur modification à un groupe restreint, ou carrément au monde entier. Encore une fois, il y a ici la garantie de Google en matière de sécurité des informations.

Voici cependant quelques mesures de sécurité qui sont offertes à l'utilisateur :

  • supprimer quelqu'un d'un site ;
  • contrôler l'accès au site ;
  • supprimer des commentaires et des pièces jointes ;
  • système de login avec mot de passe.

En matière de mot de passe il est à noter qu'il s'agit d'avoir sous la main trois types de mot de passe selon leur utilité : un pour des applications banales sans importance que vous utilisez, l'autre pour des applications personnelles (ex. e-mail), et l'autre enfin si possible plus complexes pour des informations hautement importantes et confidentielles que vous désirez gérer depuis Internet (ex. accès pour un site bancaire).

Ouverture à un PC distant

Par défaut le serveur MySQL n'écoute pas sur le réseau. Pour changer cela, il faut préciser son IP publique dans la configuration[2] :

vim /etc/mysql/mysql.conf.d/mysqld.cnf

ajouter ou modifier la ligne :

bind-address = MonIPPublique

Si le problème persiste, vérifier que le port 3306 est bien ouvert sur le pare-feu.

Références