Maison >développement back-end >tutoriel php >L'une des interdictions complètes des attaques par injection SQL en PHP
Dans cette série d'articles, nous expliquerons en détail comment interdire complètement les attaques par injection SQL dans l'environnement de développement PHP et donnerons un exemple de développement spécifique.
1. Introduction
PHP est un langage de script côté serveur puissant mais facile à apprendre, même les programmeurs peu expérimentés peuvent l'utiliser pour créer des sites Web complexes et dynamiques. Cependant, il se heurte souvent à de nombreuses difficultés pour assurer la confidentialité et la sécurité des services Internet. Dans cette série d'articles, nous présenterons aux lecteurs les connaissances de sécurité nécessaires au développement Web ainsi que les connaissances et le code spécifiques à PHP - vous pouvez les utiliser pour protéger la sécurité et la cohérence de vos propres applications Web. Tout d'abord, nous passons brièvement en revue les problèmes de sécurité des serveurs - montrant comment vous pouvez accéder aux informations privées dans un environnement d'hébergement partagé, éloigner les développeurs des serveurs de production, maintenir les logiciels à jour, fournir des canaux cryptés et contrôler l'accès à vos systèmes.
Nous discutons ensuite des vulnérabilités répandues dans les implémentations de scripts PHP. Nous vous expliquerons comment protéger vos scripts contre l'injection SQL, empêcher les scripts intersites et l'exécution à distance, et désactiver le « détournement » de fichiers et de sessions temporaires.
Dans le dernier article, nous mettrons en œuvre un exploit Web sécurisé. Vous apprendrez à authentifier les utilisateurs, à autoriser et à suivre les applications, à éviter la perte de données, à exécuter en toute sécurité des commandes système à haut risque et à utiliser les services Web en toute sécurité. Que vous ayez ou non une expérience suffisante dans le développement de la sécurité PHP, cette série d'articles vous fournira une mine d'informations pour vous aider à créer des applications en ligne plus sécurisées.
2. Qu'est-ce que l'injection SQL
Si vous prévoyez de ne jamais utiliser certaines données, cela ne sert à rien de les stocker dans une base de données car la base de données est conçue pour accéder et manipuler facilement les données ; dans la base de données. Cependant, si vous faites cela simplement, cela peut conduire à des catastrophes potentielles. Cette situation n'est pas importante car vous pourriez accidentellement supprimer tout ce qui se trouve dans la base de données ; c'est parce que, pendant que vous essayez d'accomplir une tâche « innocente », vous pourriez être « détourné » par quelqu'un - l'application elle-même a corrompu les données pour remplacer les vôtres. données. Nous appelons cette substitution « injection ».
En fait, chaque fois que vous demandez à l'utilisateur une entrée pour construire une requête de base de données, vous autorisez l'utilisateur à participer à la construction d'une commande pour accéder au serveur de base de données. Un utilisateur convivial pourrait se contenter d'un tel contrôle ; cependant, un utilisateur malveillant tentera d'inventer un moyen de modifier la commande, ce qui amènera la commande tordue à supprimer des données ou même à faire quelque chose de plus dangereux. En tant que programmeur, votre tâche consiste à trouver un moyen d’éviter de telles attaques malveillantes.
3. Comment fonctionne l'injection SQL
Structurer une requête de base de données est un processus très simple. Généralement, il sera mis en œuvre selon les lignes suivantes. Juste pour clarifier le titre, nous supposerons que vous disposez d'une table de base de données sur les vins 'vins' avec un champ 'variété' (c'est-à-dire le type de vin) :
1. Fournir un formulaire - Autoriser les utilisateurs de soumettre certains contenus à rechercher. Supposons que l'utilisateur choisisse de rechercher des vins de type « lagrein ».
2. Récupérez le terme de recherche de l'utilisateur et conservez-le - en l'attribuant à une variable comme celle-ci :
$variety = $_POST['variety' ];
La valeur de la variable $variety est donc maintenant :
lagrein
3. Ensuite, appliquez la variable dans la clause WHERE Structurez une requête de base de données :
$query = 'SELECT * FROM wines WHERE variété='$variety';
Ainsi, la valeur de la variable $query ressemble maintenant à ceci :
SELECT * FROM wines WHERE variété='lagrein'
4. Soumettez la requête au serveur MySQL.
5. MySQL renvoie tous les enregistrements de la table des vins - parmi eux, la valeur de la variété du champ est 'lagrein'.
À présent, cela devrait être un processus familier et simple. Malheureusement, parfois, les processus que nous connaissons et avec lesquels nous sommes à l’aise peuvent facilement conduire à des sentiments de fierté. Maintenant, réanalysons la requête que nous venons de construire.
1. La partie fixe de la requête que vous créez se termine par un guillemet simple, que vous utiliserez pour décrire le début de la valeur de la variable :
$query = 'SELECT * FROM wines WHERE variété = '';
2. Appliquer la partie fixe d'origine et contenir la valeur de la variable soumise par l'utilisateur :
$query .= $variety; . Ensuite, vous utilisez un autre guillemet simple pour connecter ce résultat - décrivant la fin de la valeur de la variable :
$ query .= ''';
Ainsi, la valeur de $query ressemble à . ceci :
SELECT * FROM vins WHERE variété = 'lagrein'
Le succès de cette structure dépend de la contribution de l'utilisateur. Dans cet exemple, vous utilisez un seul mot (ou éventuellement un groupe de mots) pour désigner un type de vin. Par conséquent, la requête est construite sans aucun en-tête et le résultat est celui auquel vous vous attendez : une liste de vins avec le type de vin « lagrein ». Maintenant, imaginons qu'au lieu de saisir un simple type de vin de type 'lagrein', votre utilisateur saisisse ce qui suit (notez les deux signes de ponctuation inclus) :
lagrein' ou 1=1;
Maintenant, vous continuez à structurer votre requête en utilisant les parties précédemment fixées (ici, nous affichons uniquement la valeur résultat de la variable $query) :
SELECT * FROM wines WHERE variete = '
Vous le concaténez ensuite en utilisant la valeur de la variable contenant la saisie utilisateur (affichée ici en gras) :
SELECT * FROM wines WHERE variete = 'lagrein' or 1=1;
Enfin, ajoutez les guillemets inférieurs et supérieurs :
SELECT * FROM wines WHERE variété = 'lagrein' or 1=1;'
Par conséquent, les résultats de la requête seront assez différents de vos attentes. En fait, votre requête contient désormais non pas une mais deux instructions, car le dernier point-virgule saisi par l'utilisateur a terminé la première instruction (sélection d'enregistrement) et commencé une nouvelle instruction. Dans ce cas, la deuxième instruction n’a aucune signification autre qu’un simple guillemet simple ; cependant, la première instruction n’est pas non plus ce que vous souhaitez implémenter ; Lorsque l'utilisateur met un guillemet simple au milieu de sa saisie, il finit par regarder la valeur de la variable et introduit une autre condition. Ainsi, au lieu de récupérer les enregistrements dont la variété est « lagrein », nous récupérons les enregistrements qui satisfont à l'un ou l'autre de deux critères (le premier est le vôtre et le second est le sien - la variété est « lagrein » ou 1. C'est l'enregistrement de 1). Puisque 1 vaut toujours 1, vous récupérerez donc tous les enregistrements !
En pratique, permettre à vos utilisateurs de voir tous les enregistrements plutôt que seulement certains d'entre eux peut sembler compliqué au début, mais en réalité, c'est le cas ; voir Atteindre tous les enregistrements peut facilement lui fournir des informations sur le système interne. structure du tableau, lui fournissant ainsi une référence importante pour atteindre des objectifs plus malveillants à l'avenir. La situation que nous venons de décrire serait particulièrement vraie si votre base de données contenait, au lieu des informations apparemment anodines sur l'alcool, une liste des revenus annuels des employés.
D'un point de vue théorique, ce genre d'attaque est en effet une chose terrible. En injectant du contenu inattendu dans votre requête, cet utilisateur peut transformer l'accès à votre base de données pour atteindre ses propres objectifs. Alors maintenant, votre base de données lui est ouverte – comme à vous.
4. Injection PHP et MySQL
Comme nous l'avons décrit précédemment, PHP, de par sa propre conception, ne fait rien de spécial - sauf de fonctionner selon vos instructions. Par conséquent, s’il est utilisé par un utilisateur malveillant, il « acceptera » une attaque spécialement conçue sur demande – comme celle que nous avons décrite précédemment.
Nous allons supposer que vous ne construirez pas intentionnellement ou même accidentellement une requête de base de données ayant des conséquences dommageables - nous supposerons donc que le problème réside dans la saisie de vos utilisateurs. Examinons maintenant de plus près les différentes manières dont les utilisateurs peuvent fournir des informations à votre script.
5. Types de saisie utilisateur
De nos jours, les actions que les utilisateurs peuvent entreprendre pour affecter vos scripts sont devenues de plus en plus complexes.
La source de saisie utilisateur la plus évidente est bien sûr un champ de saisie de texte sur un formulaire. En utilisant un tel champ, vous encouragez littéralement un utilisateur à saisir des données arbitraires. De plus, vous offrez à l'utilisateur une large plage de saisie ; vous n'avez aucun moyen de limiter à l'avance le type de données qu'un utilisateur peut saisir (même si vous pouvez choisir de limiter sa longueur). C'est pourquoi la plupart des attaques par injection proviennent de champs de formulaire non défendus.
Cependant, il existe d'autres sources d'attaques, et si vous y réfléchissez un instant, vous penserez à une technique cachée en arrière-plan du formulaire - la méthode POST ! En analysant brièvement l'URI affiché dans la barre d'outils de navigation du navigateur, un utilisateur observateur peut facilement voir quelles informations sont transmises à un script. Bien que ces URI soient généralement générés par programme, rien n'empêche un utilisateur malveillant de simplement saisir un URI avec une valeur de variable inappropriée dans un navigateur - et ainsi de se cacher pour ouvrir une base de données qui pourrait potentiellement être utilisée à mauvais escient.
Une stratégie courante pour limiter la saisie de l'utilisateur consiste à fournir une zone de sélection dans un formulaire au lieu d'une zone de saisie. Ce type de contrôle peut forcer l'utilisateur à choisir parmi un ensemble de valeurs prédéfinies et peut l'empêcher de saisir du contenu qui n'est pas visible dans une certaine mesure. Mais tout comme un attaquant peut « usurper » un URI (c'est-à-dire créer un URI qui imite un URI fiable mais invalide), il peut également usurper l'identité de votre formulaire et en créer sa propre version, et donc créer une nouvelle version de l'URI dans la boîte d'option Appliquer des sélections illégales au lieu des sélections sécurisées prédéfinies. Pour ce faire, c'est extrêmement simple : il lui suffit de regarder le code source, puis de copier et coller le code source du formulaire - et la porte s'ouvre alors pour lui.
Après avoir modifié la sélection, il pourra soumettre le formulaire et ses commandes invalides seront acceptées comme s'il s'agissait des commandes originales. Par conséquent, l’utilisateur peut utiliser de nombreuses méthodes différentes pour tenter d’injecter du code malveillant dans un script.
Ce qui précède est l'un des contenus de l'interdiction totale des attaques par injection SQL dans PHP pour. plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !