Cómo prevenir la inyección de SQL usando Python
Por supuesto, no quiero discutir aquí cómo otros lenguajes evitan la inyección SQL. Existen varios métodos para evitar la inyección de PHP en Internet y los métodos de Python son en realidad similares. Te daré un ejemplo aquí.
La causa más común de vulnerabilidades es la concatenación de cadenas. Por supuesto, la inyección SQL no es solo un caso de empalme, sino que también puede tener muchos tipos, como inyección de bytes amplios, escape de caracteres especiales, etc. Aquí, hablemos de la concatenación de cadenas más común, que también es el error más común cometido por los programadores junior.
Primero, definamos una clase que maneje las operaciones de MySQL.
Base de datos de categorías:
Nombre de host='127 0 1'
Usuario="root"
Contraseña= '. root'
db ='python tab'
charset ='utf8'
Definir inicialización (self):
self conexión. = mysqldb.connect(self.hostname, self.user, self.contraseña, self.db, charset=self.charset)
self.cursor = self conexión. p>Definir inserción(self, query):
Pruebe:
self.cursor.execute(query)
self.connection.commit() p>
Con excepciones, e:
Imprimir e
self.connection.rollback()
definir consulta(self, query):
cursor = self . conexión . cursor (mysqldb . cursors . dict cursor)
cursor.execute (consulta)
return cursor.fetchall()
def del(self):
¿Hay algún problema con la clase self.connection.close()?
La respuesta es: ¡sí!
Esta clase es defectuosa y puede conducir fácilmente a una inyección SQL. Hablemos de por qué ocurre la inyección SQL.
Para verificar la autenticidad del problema, escriba un método aquí para llamar al método en la clase anterior. Si hay un error, se lanzará una excepción directamente.
Defina la consulta de prueba (testUrl):
mysql=database()
Pruebe:
consulta SQL="SELECT * FROM ` artículo ` WHERE URL ='"+testUrl+"""
canales = consulta MySQL (consulta SQL)
Canales de retorno
Con excepciones, e:
Imprimir e es un método muy simple. Una de las declaraciones de consulta de selección más comunes también utiliza la concatenación de cadenas más simple para formar una declaración SQL. Obviamente, el parámetro pasado testUrl es controlable. agregue una comilla simple después del valor de testUrl para realizar una prueba de inyección de SQL. No hace falta decir que debe haber una vulnerabilidad de inyección. Ejecute el script y vea cuáles son los resultados.
(1064, "Hay un error en su sintaxis SQL; consulte el manual correspondiente a la versión de su servidor MariaDB para conocer la sintaxis correcta a utilizar cerca de la línea 1 "t.tips"
Error de eco, error común, los parámetros de prueba que paso aquí son
t.tips
Permítanme hablar primero sobre una situación que conduce a la inyección y modificar ligeramente el método anterior.
Defina consulta de prueba (testUrl):
mysql = base de datos()
Pruebe:
consulta SQL = ("SELECT * FROM ` artículo ` WHERE URL = '% s' "% testUrl)
canales = MySQL . consulta (consulta SQL)
Canales de retorno
Con excepciones, e :
El método de impresión e no usa la concatenación de cadenas directamente, pero usa %s para reemplazar los parámetros que se van a pasar. ¿No parece un sql precompilado? ¿Puede escribirlo así evitar la inyección de sql? ? Lo sabrás después de realizar la prueba, el eco es el siguiente
(1064, "Hay un error en tu sintaxis SQL; consulta el manual correspondiente a la versión de tu servidor MariaDB para averiguarlo en la línea 1" t. tips"
Igual que los resultados de la prueba anterior, por lo que este método no es factible y el método no es una declaración SQL precompilada, entonces, ¿qué se puede hacer para evitar la inyección de SQL?
>Solución para dos soluciones
1》 Codifique y escape los parámetros entrantes
2>Utilice el método propio del módulo MySQLdb de Python
La primera solución existe en muchos PHP. métodos anti-inyección, que escapan o filtran caracteres especiales.
La segunda solución es utilizar un método interno, algo como esto. Para PDO en PHP, la clase de base de datos anterior se puede modificar simplemente. >
Código modificado
Base de datos de categorías:
Hostname='127.0 0 1'
Usuario="root"
db ='python tab'
charset = 'utf8'
Inicialización de definición (self):
self .conexión = mysqldb .connect(self .hostname, self.user, self.contraseña, self.db, charset=self .charset)
self cursor = self cursor () /p>
Defina inserción (self, consulta, parámetros):
Pruebe:
self.cursor.execute(consulta, parámetros)
self .connection.commit()
Con excepciones, e:
Imprimir e
self.connection.rollback()
Definir consulta (self, consulta, parámetros):
cursor = self .cursor (mysqldb. cursors. dict cursor)
cursor.execute(consulta, parámetros)
return cursor.fetchall()
def del(self):
Self.connection.close() Aquí, cuando se ejecuta, se pasan dos parámetros, el primero es el declaración SQL parametrizada, y la segunda es el valor del parámetro real correspondiente. La función manejará los valores de los parámetros pasados en consecuencia para evitar la inyección de SQL. El método real es el siguiente.
preUpdateSql = "ACTUALIZAR ` artículo ` SET título=%s, fecha=%s, cuerpo=%s, donde id=%s"
MySQL insert(preUpdateSql, [. título, fecha, contenido, ayuda])
Esto evita la inyección de SQL. Después de pasar una lista, el módulo MySQLdb serializará la lista en tuplas y luego escapará de ellas.