Maison >développement back-end >Tutoriel Python >Introduction à la méthode Python pour empêcher l'injection SQL

Introduction à la méthode Python pour empêcher l'injection SQL

巴扎黑
巴扎黑original
2017-08-18 17:05:561653parcourir

Avant-propos

La vulnérabilité Web numéro un est SQL. Quel que soit le langage utilisé pour le développement back-end Web, tant qu'une base de données relationnelle est utilisée, des attaques par injection SQL peuvent être rencontrées. Alors, comment l'injection SQL apparaît-elle lors du développement Web Python et comment résoudre ce problème ?

Bien sûr, je ne veux pas discuter de la façon dont d'autres langages évitent l'injection SQL. Il existe différentes méthodes pour empêcher l'injection en PHP sur Internet. La méthode de Python est en fait similaire. Ici, je vais donner un exemple. .

Cause

La cause la plus courante des vulnérabilités est l'épissage de chaînes. Bien sûr, l'injection SQL n'est pas seulement un cas d'épissage, mais aussi l'injection d'octets larges et l'échappement de caractères spéciaux. , mais nous parlerons ici de la concaténation de chaînes la plus courante, qui est également l'erreur la plus courante pour les programmeurs débutants.

Nous définissons d'abord une classe pour gérer les opérations MySQL

class Database:
    hostname = '127.0.0.1'
    user = 'root'
    password = 'root'
    db = 'pythontab'
    charset = 'utf8'
    def __init__(self):
        self.connection = MySQLdb.connect(self.hostname, self.user, self.password, self.db, charset=self.charset)
        self.cursor = self.connection.cursor()
    def insert(self, query):
        try:
            self.cursor.execute(query)
            self.connection.commit()
        except Exception, e:
            print e
            self.connection.rollback()
    def query(self, query):
        cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute(query)
        return cursor.fetchall()
    def __del__(self):
        self.connection.close()

Y a-t-il un problème avec cette classe ?

La réponse est : Oui !

Cette classe est défectueuse et peut facilement provoquer une injection SQL. Parlons de la raison pour laquelle l'injection SQL se produit.

Afin de vérifier l'authenticité du problème, écrivez ici une méthode pour appeler la méthode de la classe ci-dessus. Si une erreur se produit, une exception sera levée directement.

def test_query(testUrl):
    mysql = Database()
    try:
        querySql = "SELECT * FROM `article` WHERE url='" + testUrl + "'"
        chanels = mysql.query(querySql)
        return chanels
    except Exception, e:
        print e

Cette méthode est très simple. L'une des instructions de requête de sélection les plus courantes utilise également la concaténation de chaînes la plus simple pour former une instruction SQL. Il est évident que le paramètre testUrl transmis est contrôlable si vous le souhaitez. pour effectuer des tests d'injection, il vous suffit d'ajouter un guillemet simple après la valeur de testUrl pour effectuer le test d'injection SQL. Inutile de dire qu'il doit y avoir une vulnérabilité d'injection. Exécutez le script et voyez quel est le résultat

(1064, "Vous avez une erreur dans votre syntaxe SQL ; consultez le manuel qui correspond à la version de votre serveur MariaDB pour connaître la bonne syntaxe à utiliser près de ''t.tips''' à la ligne 1")

Le message d'erreur s'affiche, il semble familier Erreur, les paramètres de test que j'ai transmis ici sont

t.tips'

Parlons d'une autre situation qui conduit à l'injection Après avoir légèrement modifié ce qui précède. method

def test_query(testUrl):
    mysql = Database()
    try:
        querySql = ("SELECT * FROM `article` WHERE url='%s'" % testUrl)
        chanels = mysql.query(querySql)
        return chanels
    except Exception, e:
        print e
Cette méthode n'utilise pas directement la concaténation de chaînes, mais utilise %s pour remplacer les paramètres à transmettre. Cela ne ressemble-t-il pas beaucoup à du SQL précompilé ? Cette façon d’écrire peut-elle empêcher l’injection SQL ? Vous le saurez après l'avoir testé. La réponse est la suivante

(1064, "Vous avez une erreur dans votre syntaxe SQL ; consultez le manuel qui correspond à la version de votre serveur MariaDB pour connaître la bonne syntaxe à utiliser près de''). t.tips' '' à la ligne 1")

Les résultats sont les mêmes que le test ci-dessus, donc cette méthode n'est pas possible, et cette méthode n'est pas une instruction SQL précompilée, alors que peut-on faire pour éviter injection SQL ?

Solution

Deux solutions

1> Encoder et échapper les paramètres entrants

2> 🎜>La première solution est en fait incluse dans de nombreuses méthodes d'anti-injection PHP, qui consiste à échapper ou filtrer les caractères spéciaux.

La deuxième option consiste à utiliser des méthodes internes, similaires au PDO en PHP. Ici, vous pouvez simplement modifier la classe de base de données ci-dessus.

Code modifié

Ici, exécutez des passes dans deux paramètres lors de l'exécution. Le premier est l'instruction SQL paramétrée et la seconde est la valeur réelle du paramètre correspondante, la fonction traitera le. a transmis la valeur du paramètre en conséquence pour empêcher l'injection SQL. La méthode réelle utilisée est la suivante

class Database:
    hostname = '127.0.0.1'
    user = 'root'
    password = 'root'
    db = 'pythontab'
    charset = 'utf8'
    def __init__(self):
        self.connection = MySQLdb.connect(self.hostname, self.user, self.password, self.db, charset=self.charset)
        self.cursor = self.connection.cursor()
    def insert(self, query, params):
        try:
            self.cursor.execute(query, params)
            self.connection.commit()
        except Exception, e:
            print e
            self.connection.rollback()
    def query(self, query, params):
        cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute(query, params)
        return cursor.fetchall()
    def __del__(self):
        self.connection.close()
preUpdateSql = "UPDATE `article` SET title=%s,date=%s,mainbody=% s WHERE id=%s"

mysql.insert(preUpdateSql, [title, date, content, aid])

Cela peut empêcher l'injection SQL Après avoir transmis une liste, le module MySQLdb En interne, la liste sera sérialisée. dans un tuple, puis l'opération d'échappement sera effectuée.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn