Comment puis-je prévenir l'injection SQL en PHP?
Si la saisie de l'utilisateur est inséré, sans modification, dans une requête SQL, puis l'application devient vulnérable à L'injection SQL, comme dans l'exemple suivant:
$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
C'est parce que l'utilisateur peut saisir quelque chose comme value'); DROP TABLE table;--
, et la requête devient:
INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
Ce qui peut être fait pour empêcher que cela se produise?
Vous devez vous connecter pour publier un commentaire.
Utiliser les requêtes préparées et des requêtes paramétrées. Ce sont des instructions SQL qui sont envoyés et analysés par le serveur de base de données séparément de tous les paramètres. De cette façon, il est impossible pour un attaquant d'injecter du SQL malveillant.
En gros, vous avez deux options pour y parvenir:
À l'aide de AOP (pour n'importe quel pilote de base de données):
À l'aide de MySQLi (pour MySQL):
Si vous vous connectez à une base de données autre que MySQL, il y a un pilote spécifique à la deuxième option que vous pouvez consulter (par exemple
pg_prepare()
etpg_execute()
pour PostgreSQL). PDO est l'option universelle.Correctement la configuration de la connexion
Noter que lors de l'utilisation de
PDO
pour accéder à une base de données MySQL réel préparées sont pas utilisé par défaut. Pour résoudre ce problème, vous devez désactiver l'émulation des déclarations préparées à l'avance. Un exemple de création d'une connexion à l'aide de PDO est:Dans l'exemple ci-dessus le mode d'erreur n'est pas strictement nécessaire, mais il est conseillé de l'ajouter. De cette façon, le script ne va pas s'arrêter avec un
Fatal Error
quand quelque chose va mal. Et il donne au développeur la possibilité decatch
toute erreur(s) qui sontthrow
nPDOException
s.Qu'est-ce que obligatoire, cependant, est le premier
setAttribute()
ligne, qui raconte PDO pour désactiver émulé déclarations préparées à l'avance et d'utiliser réel déclarations préparées à l'avance. Cela permet de s'assurer de la déclaration et les valeurs ne sont pas analysés par PHP avant de les envoyer au serveur MySQL (en donnant un éventuel attaquant aucune chance à injecter du SQL malveillant).Bien que vous pouvez définir le
charset
dans les options du constructeur, il est important de noter que les "anciennes" versions de PHP (< 5.3.6) silencieusement ignoré le paramètre charset dans la source de données.Explication
Ce qui se passe, c'est que l'instruction SQL que vous passez à
prepare
est analysé et compilé par le serveur de base de données. En spécifiant des paramètres (soit un?
ou un paramètre nommé comme:name
dans l'exemple ci-dessus) vous dites que le moteur de base de données où vous voulez filtrer. Ensuite, lorsque vous appelezexecute
, l'instruction préparée est combiné avec les valeurs des paramètres que vous spécifiez.La chose importante ici est que les valeurs des paramètres sont combinés avec l'compilé déclaration, pas une chaîne SQL. SQL injection fonctionne en incitant le script dans malveillants, y compris les chaînes lorsqu'il crée SQL afin de les envoyer à la base de données. Envoyer le réel SQL séparément à partir de ces paramètres, vous limitez le risque de se retrouver avec quelque chose que vous n'avez pas l'intention. Tous les paramètres que vous envoyez lorsque vous utilisez une instruction préparée va juste être traitées comme des chaînes (bien que le moteur de base de données peut faire quelques optimisation des paramètres peut finir comme les numéros de trop, bien sûr). Dans l'exemple ci-dessus, si le
$name
variable contient'Sarah'; DELETE FROM employees
le résultat serait tout simplement une recherche de la chaîne"'Sarah'; DELETE FROM employees"
, et vous n'aurez donc pas à une table vide.Un autre avantage de l'utilisation de déclarations préparées à l'avance, c'est que si vous exécutez le même relevé plusieurs fois dans la même session, il ne sera analysé et compilé une fois, vous donnant des gains de vitesse.
Oh, et puisque vous avez posé la question de comment faire pour l'insérer, voici un exemple (en utilisant PDO):
Peut préparées être utilisé pour les requêtes dynamiques?
Alors que vous pouvez toujours utiliser les requêtes préparées pour les paramètres de la requête, la structure de la dynamique de la requête elle-même ne peut pas être paramétrées et certaines fonctionnalités de requête ne peut pas être paramétrées.
À ces scénarios, la meilleure chose à faire est d'utiliser un filtre de liste blanche qui restreint les valeurs possibles.
Si vous utilisez une version récente de PHP, le
mysql_real_escape_string
option décrite ci-dessous n'est plus disponible (bien quemysqli::escape_string
est l'équivalent moderne). Ces jours-ci lemysql_real_escape_string
option n'a de sens que pour le code de legs sur une ancienne version de PHP.Vous avez deux options s'échapper les caractères spéciaux dans votre
unsafe_variable
, ou à l'aide d'une requête paramétrée. Les deux devraient vous protéger contre l'injection SQL. La requête paramétrée est considéré comme la meilleure pratique, mais il faudra modifier pour une nouvelle extension MySQL en PHP avant de pouvoir l'utiliser.Nous parlerons de l'impact plus faible de la chaîne échapper une première.
Voir aussi, les détails de l'
mysql_real_escape_string
fonction.À l'utilisation de la requête paramétrée, vous devez utiliser MySQLi plutôt que de la MySQL fonctions. Pour reprendre ton exemple, nous aurions besoin de quelque chose comme ce qui suit.
La touche de fonction, vous aurez envie de lire, il y aurait
mysqli::prepare
.Aussi, comme d'autres l'ont suggéré, vous trouverez peut-être utile/plus facile à l'étape d'une couche d'abstraction avec quelque chose comme AOP.
Veuillez noter que le cas vous m'avez demandé est assez simple et que les cas plus complexes peuvent nécessiter des approches plus complexes. En particulier:
mysql_real_escape_string
. Dans ce genre de cas, vous feriez mieux de passer l'entrée de l'utilisateur par le biais d'une liste blanche pour s'assurer que seuls des " sûr " les valeurs sont autorisés à traverser.mysql_real_escape_string
approche, vous allez souffrir de ce problème est décrit par Polynôme dans les commentaires ci-dessous. Ce cas est plus délicat parce que les entiers ne serait pas être entouré par des guillemets, de sorte que vous pourriez traiter par la validation de la saisie de l'utilisateur ne contient que des chiffres.mysql_real_escape_string
est assez ou je doit utiliser paramétrée trop?htmlentities
par exemplemysql_real_escape_string()
pour l'exhaustivité, mais ne suis pas un fan de la cotation la plus le risque d'erreur de première approche. Le lecteur peut rapidement saisir le premier exemple. Bonne chose, il est obsolète maintenant 🙂Chaque réponse ici ne couvre qu'une partie du problème.
En fait, il y a quatre autre requête, les pièces qui l'on peut ajouter à cette dynamique: -
Et les requêtes préparées ne couvrent que deux d'entre eux.
Mais parfois, nous devons faire notre requête encore plus dynamique, l'ajout d'opérateurs ou d'identifiants ainsi.
Donc, nous allons avoir besoin de différentes techniques de protection.
En général, une telle approche de la protection est basée sur liste blanche.
Dans ce cas, chaque paramètre dynamique doit être codé en dur dans votre script, et choisi dans l'ensemble.
Par exemple, pour faire dynamique de la commande:
Cependant, il est une autre façon de sécuriser les identificateurs d'échappement. Tant que vous avez un identifiant cité, vous pouvez échapper à backticks à l'intérieur par les doubler.
Comme un pas de plus, on peut emprunter une idée vraiment géniale de prendre de l'espace réservé (une procuration pour représenter la valeur réelle dans la requête) à partir des déclarations préparées à l'avance et d'inventer un espace réservé d'un autre type - un identifiant de l'espace réservé.
Donc, pour faire de la longue histoire courte: c'est un espace réservé, pas instruction préparée peut être considéré comme une balle d'argent.
Donc, une recommandation générale peut être présenté sous la forme d'
Aussi longtemps que vous êtes ajout dynamique de parties à la requête en utilisant des paramètres (et ces espaces réservés traitées correctement bien sûr), vous pouvez être sûr que votre requête est sûr.
Encore, il y a un problème avec la syntaxe SQL mots-clés (tels que
AND
,DESC
et par exemple), mais par liste blanche semble que la seule approche dans ce cas.Mise à jour
Bien qu'il existe un accord général sur les meilleures pratiques en matière d'injection SQL de protection, il y a encore beaucoup de mauvaises pratiques. Et certains d'entre eux trop profondément enracinée dans l'esprit des utilisateurs de PHP. Par exemple, sur cette page il y a (bien qu'invisibles à la plupart des visiteurs) plus de 80 supprimé réponses - tous éliminés par la collectivité en raison de la mauvaise qualité ou la promotion de la bad et de pratiques dépassées. Pire encore, certaines mauvaises réponses ne sont pas supprimés, mais plutôt prospère.
Par exemple, il y a(1) sont(2) encore(3) de nombreux(4) les réponses(5), y compris la deuxième plus upvoted répondre vous suggère manuel de l'échappement de la chaîne - une approche dépassée qui s'est avérée être précaire.
Ou il y a un peu plus de réponse que suggère tout une autre méthode de mise en forme de chaîne et dispose même d'elle comme la panacée ultime. Bien sûr, il ne l'est pas. Cette méthode n'est pas meilleur que celui d'une chaîne de mise en forme, et pourtant, elle garde toutes ses inconvénients: elle est applicable à cordes et, comme tout autre manuel de mise en forme, c'est essentiellement en option, non obligatoire dans la mesure, sujets à l'erreur humaine de toute sorte.
Je pense que tout cela à cause d'une très vieille superstition, pris en charge par ces autorités comme OWASP ou le manuel PHP, qui proclame l'égalité entre ce qui "s'échapper" et la protection contre les injections SQL.
Indépendamment de ce manuel PHP dit pour les âges,
*_escape_string
par aucun moyen rend la sécurité des données et n'a jamais été prévu pour. En plus d'être inutile pour SQL partie autre que celui de la chaîne, manuel de l'échappement est faux, car c'est le manuel que face à l'automatisation.Et OWASP le rend encore pire, en insistant sur la fuite des la saisie de l'utilisateur qui est un véritable non-sens: il devrait y avoir aucun de ces mots dans le contexte de l'injection de protection. Chaque variable est potentiellement dangereux, quelle que soit la source! Ou, en d'autres termes, chaque variable doit être correctement mis en forme pour être mis dans une requête, peu importe la source de nouveau. C'est la destination qui compte. Le moment où un développeur commence à séparer les brebis des chèvres (en pensant que certains variable donnée est "sûr" ou pas), il/elle prend son premier pas vers la catastrophe. Ne pas oublier que même la formulation suggère en vrac s'échapper sur le point d'entrée, ressemblant à de la la très de la magie fonctionnalité devis - déjà méprisé, obsolète et enlevé.
Ainsi, contrairement à ce qui "s'enfuir", préparées est la mesure qui protège effectivement contre l'injection SQL (le cas échéant).
Si vous n'êtes toujours pas convaincu, voici un guide étape-par-étape des explications que j'ai écrit, Le Hitchhiker's Guide to SQL Injection de prévention, où j'ai expliqué toutes ces questions en détail et même compilé une section entièrement dédiée aux mauvaises pratiques et de leur divulgation.
FILTER_SANITIZE_NUMBER_INT
permet uniquement le nombre de caractères, ce qui de liste blanche des personnages, pas toute les chaînes. En combinaison avec des déclarations préparées à l'avance, il fait un bon "ceinture et bretelles" approche.Je vous recommande d'utiliser AOP (PHP Data Objects) pour exécuter des requêtes SQL paramétrées.
Cela ne fait pas que protéger contre les injections SQL, il permet également d'accélérer les requêtes.
Et en utilisant PDO plutôt que
mysql_
,mysqli_
, etpgsql_
fonctions, vous faites de votre application un peu plus abstraite à partir de la base de données, dans de rares cas que vous devez passer des fournisseurs de bases de données.order by
malheureusement 🙁Utilisation
PDO
et les requêtes préparées.(
$conn
est unPDO
objet)Comme vous pouvez le voir, les gens vous suggérons d'utiliser les requêtes préparées tout au plus. C'est pas faux, mais si votre requête est exécutée juste une fois par processus, il y aurait une légère perte de performance.
J'ai été confronté à ce problème, mais je pense que je l'ai résolu en très manière sophistiquée - la façon dont les pirates de l'utiliser pour éviter à l'aide de citations. Je l'utilise en conjonction avec des émules déclarations préparées à l'avance. Je l'utilise pour prévenir tous sortes de possibles attaques par injection SQL.
Mon approche:
Si vous prévoyez d'entrée d'être entier assurez-vous que c'est vraiment entier. Dans une variable de type langage comme PHP c'est ce très important. Vous pouvez utiliser, par exemple, cette solution simple mais efficace:
sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);
Si vous vous attendez à rien d'autre de entier hex il. Si vous hex, vous pourrez parfaitement échapper à toutes les entrées. En C/C++ il y a une fonction appelée
mysql_hex_string()
, en PHP, vous pouvez utiliserbin2hex()
.Ne vous inquiétez pas échappé à la chaîne aura un 2x la taille de sa longueur d'origine, parce que même si vous utilisez
mysql_real_escape_string
, PHP a pour allouer de la même capacité((2*input_length)+1)
, qui est le même.Cet hex méthode est souvent utilisée lorsque vous transférez des données binaires, mais je ne vois pas de raison de ne pas l'utiliser sur toutes les données pour éviter les attaques par injection SQL. Notez que vous devez ajouter des données avec
0x
ou utiliser la fonction MySQLUNHEX
à la place.Ainsi, par exemple, la requête:
Deviendra:
ou
Hex est l'évasion parfaite. Aucun moyen de l'injection.
Différence entre UNHEX fonction et le préfixe 0x
Il y a des discussions dans les commentaires, donc je tiens enfin à préciser. Ces deux approches sont très similaires, mais ils sont un peu différentes à certains égards:
L' ** 0** préfixe peut être utilisé uniquement pour les colonnes de données telles que char, varchar, text, bloc, binaire, etc.
Aussi, son utilisation est un peu compliqué si vous êtes sur le point d'insérer une chaîne vide. Vous aurez à remplacer entièrement avec
''
, ou vous obtiendrez une erreur.UNHEX() fonctionne sur tout colonne; vous n'avez pas à vous soucier de la chaîne vide.
Hex méthodes sont souvent utilisées comme des attaques
Noter que cet hex méthode est souvent utilisée comme une attaque par injection SQL, où les entiers sont juste comme les chaînes et les échappés juste avec
mysql_real_escape_string
. Ensuite, vous pouvez éviter l'utilisation de guillemets.Par exemple, si vous venez de faire quelque chose comme ceci:
une attaque peut vous injectez très facilement. Considérez les points suivants code injecté est retourné à partir de votre script:
et maintenant il suffit d'extraire structure de la table:
Et puis il suffit de sélectionner toutes les données, celles veulent. N'est-ce pas cool?
Mais si le vendeur d'un produit injectable site hex-il, pas d'injection serait possible parce que la requête devrait ressembler à ceci:
SELECT ... WHERE id = UNHEX('2d312075...3635')
tblproducts
OÙ product_code COMME ( '%42%') ne trouve de record, mais SÉLECTIONNEZ * à PARTIR detblproducts
OÙ product_code COMME ('%' +0x3432 +'%') n'est pas le cas, cela ne fonctionne pas ou j'ai fait quelque chose de mal ?+
mais avecCONCAT
. Et de la performance: je ne pense pas que cela affecte les performances, car mysql dispose d'analyse de données et il n'importe pas si l'origine est une chaîne ou hex0x . $_GET["id"]
pour id42
entraînera octet ascii code 42. EssayezSELECT 0x42
et vous verrez ce que vous êtes.0x . $_GET["id"]
là. Mais de toute façon, il ne sera pas trouver un numéro 42 de trop'root'
ou vous pouvez hex il0x726f6f74
MAIS si vous voulez que le numéro et l'envoyer en tant que chaîne de caractères, vous aurez probablement écrire '42' pas de CHAR(42) ... '42' hex serait0x3432
pas0x42
"SELECT title FROM article WHERE id = 0x" . bin2hex($_GET["id"])
? Quel est le problème avec la représentation ici?SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ')
mysql_real_escape_string
est maintenant obsolète, de sorte que sa n'est plus une option viable. Il sera supprimé à partir de PHP dans le futur. De son mieux pour se déplacer sur ce que le PHP ou MySQL gens recommander.UNHEX()
équivalent existe dans SQL Server. S'avère que nous sommes à gauche avec quelque chose le long de ces lignes:SELECT CONVERT(VARCHAR(MAX), 0x4142)
Bien, je suppose que l'on pouvait portUNHEX()
eux-mêmes s'ils vraiment voulu.x''
de sorte que vous pouvez avoir des valeurs vides, trop!x'79656574'
- pas d'erreurs avec les cordes à vide, contrairement à0x
qui n'est pas valideInjection de prévention - mysql_real_escape_string()
PHP spécialement fait pour éviter ces attaques. Tout ce que vous devez faire est d'utiliser la taille d'une bouchée d'une fonction,
mysql_real_escape_string
.mysql_real_escape_string
prend une chaîne de caractères qui est destiné à être utilisé dans une requête MySQL et le retour de la même chaîne avec tous les injection SQL tente en toute sécurité échappé. Fondamentalement, il remplacera les ennuyeuses d'apostrophes(') un utilisateur peut entrer avec un MySQL-remplacement sécurisé, une fuite de devis \'.REMARQUE: vous devez être connecté à la base de données pour utiliser cette fonction!
//Connexion à MySQL
Vous pouvez trouver plus de détails en MySQL - SQL Injection de Prévention.
mysql_real_escape_string
but est de permettre de construire un bon de requête SQL pour chaque entrée de données de la chaîne. Prévention de l'injection de code sql est l'effet secondaire de cette fonction.mysql_real_escape_string()
n'est pas infaillible.mysql_real_escape_string
est maintenant obsolète, de sorte que sa n'est plus une option viable. Il sera supprimé dans le futur à partir de PHP. De son mieux pour se déplacer sur ce que le PHP ou MySQL gens recommander.Que vous pourriez faire quelque chose de simple comme ceci:
Cela ne va pas résoudre tous les problèmes, mais c'est un très bon tremplin. J'en ai laissé évidente des éléments tels que la vérification de la variable de l'existence, format (chiffres, lettres, etc.).
$q = "SELECT col FROM tbl WHERE x = $safe_var";
par exemple. Réglage$safe_var
à1 UNION SELECT password FROM users
fonctionne dans ce cas, en raison de l'absence de guillemets. Il est également possible d'injecter des chaînes de caractères dans la requête à l'aide deCONCAT
etCHR
.mysql_real_escape_string()
n'est pas infaillible.mysql_real_escape_string
est maintenant obsolète, de sorte que sa n'est plus une option viable. Il sera supprimé dans le futur à partir de PHP. De son mieux pour se déplacer sur ce que le PHP ou MySQL gens recommander.Ce que vous n'utilisez en fin de compte, assurez-vous de vérifier votre saisie qui n'a pas déjà été mutilé par
magic_quotes
ou d'une autre signification de la foutaise, et, si nécessaire, le lancer à traversstripslashes
ou que ce soit pour l'assainir.Requête paramétrée ET la validation des entrées est le chemin à parcourir. Il ya beaucoup de scénarios pour lesquels l'injection SQL peut se produire, même si
mysql_real_escape_string()
a été utilisé.Ces exemples sont vulnérables à l'injection SQL:
ou
Dans les deux cas, vous ne pouvez pas utiliser
'
pour protéger l'encapsulation.Source: L'Inattendu Injection SQL (Lors de l'évacuation n'Est Pas Assez)
À mon avis, la meilleure façon, généralement, de prévenir l'injection SQL dans votre application PHP (ou toute application web, d'ailleurs), c'est de penser au sujet de votre application à l'architecture. Si la seule façon de protéger contre les injections SQL est de se rappeler d'utiliser une méthode ou une fonction qui fait La bonne Chose chaque fois que vous parlez à la base de données, vous le faites mal. De cette façon, c'est juste une question de temps jusqu'à ce que vous oubliez de formater correctement votre requête à un certain moment dans votre code.
Adoptant le modèle MVC et un cadre comme CakePHP ou CodeIgniter est probablement la bonne façon de faire: les tâches Courantes, comme la création de sécuriser les requêtes de base de données ont été résolus de manière centralisée et mis en œuvre dans de tels cadres. Ils vous aideront à organiser votre application web d'une manière sensible et vous faire réfléchir plus sur le chargement et l'enregistrement des objets que solidement la construction unique des requêtes SQL.
Je préfère procédures stockées (MySQL a eu des procédures stockées depuis 5.0) à partir d'un point de vue sécurité - les avantages sont -
Les inconvénients sont -
Il existe de nombreuses façons de prévenir les injections SQL et SQL hacks. Vous pouvez facilement le trouver sur Internet (Recherche sur Google). Bien sûr AOP est l'une des bonnes solutions. Mais je voudrais vous proposer quelques bons liens de la prévention contre l'Injection SQL.
Qu'est-ce que l'injection SQL et comment les prévenir
Manuel PHP pour l'injection SQL
Microsoft explication de l'injection SQL et de prévention en PHP
et quelques autres, comme La prévention de l'injection SQL avec MySQL et PHP
Maintenant, pourquoi vous le faites, vous devez prévenir votre requête à partir de l'injection SQL?
Je voudrais savoir: Pourquoi devons-nous essayer pour la prévention de l'injection SQL avec un petit exemple ci-dessous:
Requête pour l'authentification de la connexion de match:
Maintenant, si quelqu'un (un pirate) met
et mot de passe rien....
La requête sera analysée dans le système jusqu'à:
L'autre partie seront rejetées. Donc, ce qui va arriver? Un non-utilisateur autorisé (hacker) sera en mesure de se connecter en tant qu'administrateur sans avoir son mot de passe. Maintenant, il peut faire tout ce que admin/e-mail personne peut faire. Voir, c'est très dangereux si l'injection SQL n'est pas empêché.
Je pense que si quelqu'un veut utiliser PHP et MySQL ou quelque autre serveur de base de données:
(int)$foo
. Lire plus sur le type de variables en PHP ici. Si vous utilisez des bibliothèques comme PDO ou MySQLi, utilisez toujours PDO::quote() et mysqli_real_escape_string().Bibliothèques exemples:
---- AOP
--- MySQLi
P. S:
AOP gagne cette bataille avec la facilité. Avec le soutien de douze
les différents pilotes de base de données et les paramètres nommés, nous pouvons ignorer l'
petite perte de performance, et de s'habituer à son API. En matière de sécurité
point de vue, deux d'entre eux sont en sécurité tant que le développeur utilise
la façon dont ils sont censés être utilisés
Mais alors que les deux PDO et MySQLi sont assez rapide, MySQLi effectue
pas significativement plus rapide dans les benchmarks – ~2,5% pour les non-préparés
états, et ~6,5% pour ceux préparés.
Et s'il vous plaît tester chaque requête à votre base de données - c'est une meilleure façon de prévenir l'injection.
Si possible, cast le type de vos paramètres. Mais c'est seulement en travaillant sur les types simples comme int, bool, et de flotter.
Si vous voulez prendre avantage de les moteurs de cache, comme Redis ou Memcached, peut-être DALMP pourrait être un choix. Il utilise pure MySQLi. Vérifiez ceci: DALMP Couche d'Abstraction de Base de MySQL à l'aide de PHP.
Aussi, vous pouvez préparer vos arguments avant de préparer votre requête, de sorte que vous pouvez construire des requêtes dynamiques et à la fin ont entièrement préparées requête. DALMP Couche d'Abstraction de Base de MySQL à l'aide de PHP.
Pour ceux incertain de la façon d'utiliser PDO (venant de la
mysql_
fonctions), j'ai fait un très, très simple AOP wrapper qui est un fichier unique. Il existe pour montrer comment il est facile de faire toutes les choses les demandes doivent être faites. Fonctionne avec PostgreSQL, MySQL et SQLite.Fondamentalement, lire pendant que vous lisez le manuel pour voir comment mettre de la PDO fonctions à utiliser dans la vraie vie pour faire simple pour stocker et récupérer des valeurs dans le format vous souhaitez.
À l'aide de cette fonction PHP
mysql_escape_string()
vous pouvez obtenir une bonne prévention dans une voie rapide.Par exemple:
mysql_escape_string
Échappe une chaîne pour l'utiliser dans un mysql_queryPour plus de prévention, vous pouvez ajouter à la fin ...
Enfin, vous bénéficiez de:
Quelques lignes directrices pour échapper les caractères spéciaux dans les instructions SQL.
Ne pas utiliser MySQL, cette extension est obsolète, utilisez MySQLi ou AOP.
MySQLi
De la main à échapper les caractères spéciaux dans une chaîne de caractères, vous pouvez utiliser le mysqli_real_escape_string fonction. La fonction ne fonctionnera pas correctement si le jeu de caractères correct est défini avec mysqli_set_charset.
Exemple:
Automatique s'échapper de valeurs avec les requêtes préparées, utilisez mysqli_prepare, et mysqli_stmt_bind_param où le type de la lier les variables doivent être fournis pour une conversion appropriée:
Exemple:
Peu importe si vous utilisez les instructions préparées ou mysqli_real_escape_string, vous avez toujours de connaître le type de données d'entrée que vous utilisez.
Donc si vous utilisez une instruction préparée, vous devez spécifier les types des variables pour mysqli_stmt_bind_param fonction.
Et l'utilisation de mysqli_real_escape_string est pour, comme son nom l'indique, l'échappement des caractères spéciaux dans une chaîne de caractères, de sorte qu'il ne sera pas faire des entiers coffre-fort. Le but de cette fonction est d'empêcher la rupture des cordes dans les instructions SQL, et les dommages causés à la base de données qu'il pouvait provoquer. mysqli_real_escape_string est une fonction utile lorsqu'il est utilisé correctement, surtout lorsqu'il est combiné avec sprintf.
Exemple:
La simple alternative à ce problème pourrait être résolu par l'octroi des autorisations appropriées dans la base de données elle-même.
Par exemple: si vous utilisez une base de données MySQL puis entrez dans la base de données par le biais du terminal ou de l'INTERFACE utilisateur fournie et il suffit de suivre cette commande:
Cela permettra de limiter l'utilisateur à obtenir enfermé avec la requête spécifiée uniquement. Supprimer l'autorisation de supprimer et de sorte que les données ne seraient jamais être supprimés de la requête tiré à partir de la page PHP.
La deuxième chose à faire est de rincer les privilèges de sorte que le MySQL actualise les autorisations et les mises à jour.
plus d'informations sur rincer.
Pour voir les privilèges de l'utilisateur de feu, la requête suivante.
En savoir plus sur SUBVENTION.
select id, name from dropdown_table where status = '$YOUR_STATUS_VARIABLE$';
Maintenant, passer1' union all select id, email from users --
que $YOUR_STATUS_VARIABLE$ et vous verrez comment il fonctionne.J'utilise trois différentes façons de prévenir mon application web d'être vulnérable à une injection SQL.
mysql_real_escape_string()
, qui est un pré-définis en fonction PHP, et ce code d'ajouter des barres obliques inverses pour les caractères suivants:\x00
,\n
,\r
,\
,'
,"
et\x1a
. Transmettre les valeurs d'entrée en tant que paramètres pour minimiser le risque d'injection SQL.J'espère que cela va vous aider.
Considérons la requête suivante:
$iId = mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";
mysql_real_escape_string() ne protège pas ici. Si vous utilisez des guillemets simples (' ') autour de vos variables à l'intérieur de votre requête est ce qui vous protège contre ce. Voici une solution ci-dessous pour ceci:
$iId = (int) mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";
Ce question a quelques bonnes réponses à ce sujet.
Je suggère, en utilisant PDO est la meilleure option.
Edit:
mysql_real_escape_string()
est obsolète depuis PHP 5.5.0. Utiliser mysqli ou PDO.Une alternative à mysql_real_escape_string() est
Exemple:
Concernant beaucoup de réponses utiles, je l'espère, pour ajouter des valeurs à ce fil.
L'injection SQL est une attaque qui peut être fait à travers l'utilisation d'intrants (Inputs qui rempli par l'utilisateur, puis utilisé à l'intérieur de requêtes), L'injection SQL modèles sont corriger la syntaxe de la requête, alors que nous pouvons appeler: mauvais requêtes pour de mauvaises raisons, nous supposons qu'il existe peut-être une mauvaise personne que d'essayer d'obtenir des informations secrètes (sans passer par le contrôle d'accès) qui affectent les trois principes de la sécurité (Confidentialité, Intégrité, Disponibilité).
Maintenant, notre but est de prévenir les menaces de sécurité telles que les attaques par injection SQL, la question (Comment éviter les attaques par injection SQL à l'aide de PHP), soit plus réaliste, le filtrage de données ou de compensation des données d'entrée est le cas lors de l'utilisation par l'utilisateur des données d'entrée à l'intérieur de cette requête, à l'aide de PHP ou tout autre langage de programmation n'est pas le cas, ou comme recommandé par plus de personnes à utiliser les techniques modernes telles que la déclaration ou tout autre outils qui soutiennent actuellement l'injection SQL de prévention, de considérer que ces outils n'est plus disponible? Comment sécuriser votre application?
Mon approche contre l'injection SQL est: l'effacement de l'utilisateur des données d'entrée avant de l'envoyer à la base de données (avant de l'utiliser à l'intérieur de la requête).
Filtrage des données pour la Conversion dangereux de données de sécurité des données)
Considérer que AOP et MySQLi pas disponibles, comment pouvez-vous sécuriser votre application? - Vous me forcer à les utiliser? Quelles sont les autres langues autres que PHP? Je préfère donner des idées, car il peut être utilisé pour la plus large de la frontière et pas seulement pour des langues spécifiques.
RÈGLE: ne pas créer un utilisateur de base de données pour tous les privilèges, pour toutes les opérations SQL, vous pouvez créer votre régime comme (deluser, selectuser, updateuser) que les noms d'utilisateur pour l'usage facile.
voir Principe du moindre privilège
Filtrage des données: avant de construire la requête saisie de l'utilisateur doit être validé et filtrée, pour les programmeurs, il est important de définir quelques propriétés pour chaque utilisateur les variables d'entrée:
type de données, le modèle de données, et les données de longueur. un champ est un nombre entre (x et y) doit être exactement validé à l'aide de règle précise, pour un champ est une chaîne de caractères (texte): le motif est le cas, par exemple, le nom d'utilisateur doit contenir seulement certains caractères permet de dire que [a-zA-Z0-9_-.] la longueur varie entre (x et n) où x et n (entiers, x <=n ).
Règle: la création exacte des filtres et des règles de validation sont les meilleures pratiques pour moi.
Utiliser d'autres outils: Ici, je vais également d'accord avec vous que l'instruction préparée (paramétrées requête) et les procédures Stockées, les inconvénients ici est de ces moyens nécessite des compétences qui n'existent pas pour la plupart des utilisateurs, l'idée de base ici est de faire la distinction entre les requêtes SQL et les données qui sont utilisées à l'intérieur, les deux approches peuvent être utilisées, même à l'insécurité des données, car l'utilisateur-données d'entrée ici de ne pas ajouter quoi que ce soit à la requête d'origine tels que (tout ou x=x).
Pour plus d'informations, veuillez lire OWASP SQL Injection de Prévention de la Feuille de Triche.
Maintenant, si vous êtes un utilisateur avancé, de commencer à utiliser ce moyen de défense que vous voulez, mais, pour les débutants, s'ils ne peuvent pas mettre en œuvre rapidement la procédure stockée et prépare la déclaration, il est préférable de filtrer les données d'entrée autant qu'ils le peuvent.
Enfin, considérons que l'utilisateur envoie ce texte ci-dessous au lieu d'entrer son nom d'utilisateur:
Cette entrée peut être vérifié en début sans aucune déclaration préparée à l'avance et les procédures stockées, mais pour être sur le côté sûr, leur utilisation commence lorsque l'utilisateur-données de filtrage et de validation.
Le dernier point est de détecter un comportement inattendu qui nécessite plus d'effort et de la complexité; elle n'est pas recommandée pour la majorité des applications web.
Un comportement inattendu dans au-dessus de la saisie de l'utilisateur est de SÉLECTIONNER, de l'UNION, SI, SUBSTRING, l'indice de RÉFÉRENCE, SHA, racine une fois ces mots détectés, vous pouvez éviter l'entrée.
UPDATE1:
Un utilisateur a fait observer que ce post est inutile, OK! Voici ce que OWASP.ORG fournis:
Comme vous le savez peut-être, revendiquant un article doit être pris en charge par un argument valide, au moins une référence! Sinon, c'est considéré comme une attaque, mauvaise revendication!
Update2:
Du manuel PHP, PHP: Préparé États - Manuel:
Update3:
J'ai créé des cas de test pour savoir comment PDO et MySQLi envoyer la requête au serveur MySQL lors de l'utilisation de l'instruction préparée:
PDO:
Journal De La Requête:
MySQLi:
Journal De La Requête:
Il est clair qu'une instruction préparée est également échapper aux données, rien d'autre.
Comme mentionné dans la déclaration ci-dessus
The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly
, donc, cela prouve que la validation des données telles queintval()
est une bonne idée pour les valeurs entières avant d'envoyer une requête, en outre, de prévenir l'utilisateur malveillant de données avant l'envoi de la requête est correct et valide l'approche.Reportez-vous à cette question pour plus de détails: AOP envoie raw requête à MySQL alors que Mysqli envoie requête préparée, à la fois de produire le même résultat
Références:
Un moyen simple serait d'utiliser un framework PHP comme CodeIgniter ou Laravel qui ont intégré des fonctionnalités comme le filtrage et la vie active, enregistrement de sorte que vous n'avez pas à vous soucier de ces nuances.
* * * * Avertissement: l'approche décrite dans cette réponse s'applique uniquement aux scénarios très précis, et n'est pas sécurisé car les attaques par injection SQL ne reposent pas seulement sur le fait d'être en mesure d'injecter
X=Y
.**Si les attaquants tentent de pirater le formulaire via PHP
$_GET
variable ou avec l'adresse URL de la chaîne de requête, vous serez en mesure de les rattraper si ils ne sont pas sécurisés.Parce que
1=1
,2=2
,1=2
,2=1
,1+1=2
, etc... sont les questions les plus courantes à une base de données SQL d'un attaquant. Peut-être aussi qu'il est utilisé par beaucoup de piratage des applications.Mais vous devez être prudent que vous ne devez pas réécrire un coffre-fort requête à partir de votre site. Le code ci-dessus vous donne une astuce, à réécrire ou de redirection (cela dépend de vous) que le piratage spécifique à la dynamique de la chaîne de requête dans une page qui va stocker l'attaquant Adresse IP, ou MÊME les COOKIES, l'historique du navigateur, ou toute autre information sensible, de sorte que vous pouvez traiter avec eux plus tard par l'interdiction de leur compte ou de contact avec les autorités.
Il ya tellement de nombreuses réponses PHP et MySQL, mais ici, c'est le code pour PHP et Oracle pour prévenir l'injection SQL ainsi que l'utilisation régulière de oci8 pilotes:
Une bonne idée est d'utiliser un 'object-relational mapper' comme Idiorm:
Il n'économise pas seulement à partir des injections SQL, mais à partir des erreurs de syntaxe trop! Prend également en charge des collections de modèles avec chaînage de méthode à filtre ou d'appliquer des mesures de résultats multiples à la fois et les connexions multiples.
À l'aide de AOP et MYSQLi est une bonne pratique pour éviter des injections SQL, mais si vous voulez vraiment travailler avec les fonctions de MySQL et des requêtes, il serait préférable d'utiliser
mysql_real_escape_string
Il y a plus de capacités pour empêcher cela: comme les identifier - si l'entrée est une chaîne de caractères, nombre, char ou un tableau, il y en a tellement intégré les fonctions permettant de détecter cette. Aussi, il serait préférable d'utiliser ces fonctions pour vérifier les données d'entrée.
is_string
is_numeric
Et c'est tant mieux pour utiliser ces fonctions pour vérifier les données d'entrée avec
mysql_real_escape_string
.mysql_real_escape_string()
n'est pas infaillible.mysql_real_escape_string
est maintenant obsolète, de sorte que sa n'est plus une option viable. Il sera supprimé à partir de PHP dans le futur. De son mieux pour se déplacer sur ce que le PHP ou MySQL gens recommander.J'ai écrit cette petite fonction il y a plusieurs années:
Cela permet l'exécution des instructions dans un one-liner C#-ish Chaîne.Format:
Il s'échappe en considérant le type de variable. Si vous essayez de paramétrer la table, la colonne des noms, il ne pourrait pas parce qu'elle met chaque chaîne de caractères entre guillemets, qui est une syntaxe non valide.
Mise à JOUR de SÉCURITÉ: La précédente
str_replace
version autorisée injections en ajoutant {#} jetons dans les données de l'utilisateur. Cettepreg_replace_callback
version n'a pas de problème si le remplacement contient ces jetons.