IIC2413 / Syllabus-2021-2

Contenido del curso Bases de datos del DCC PUC versión 2021-2
62 stars 44 forks source link

Consulta 2.1.9 : Sanitización #257

Open aacampos3 opened 2 years ago

aacampos3 commented 2 years ago

Hola! Estaba resolviendo el ejercicio 2.1.9 (Model.select(columns:List)) y por lo menos la manera en que lo pensé es que columns podría ser de la siguiente manera columns = ["nombre", "id_distrito"] en el ejemplo de convencionales. Por lo que al tener texto debería parametrizarlo ("sanitizar"), pero obtengo un error. Un ejemplo de resultado, en mi programa, es [('nombre',), ('nombre',), ('nombre',)], donde nombre es el atributo que quiero seleccionar y no el nombre de cada convencional. Entonces, ¿es necesario "sanitizar" los atributos? o tengo un error en el programa. Gracias!

rjherrera commented 2 years ago

como se explica en https://github.com/IIC2413/Syllabus-2021-2/issues/243#issuecomment-962132698, lo que deberías obtener al usar Distrito.select(['nombre']) es una lista pero de instancias, no de tuplas, y lo que tiene que tener cada instancia es el valor correcto, es decir, si tu base de datos tiene 2 convencionales con nombre Mario y Roberto, deberías obtener una lista con 2 instancias de Convencionales, cada una con el nombre cargado. Es decir podrías hacer:

convencionales = Convencional.select(['nombre'])
for conv in convencionales:
    print(conv.nombre)

y debería entregar

Mario
Roberto

no entiendo bien a lo que te refieres con sanitizar en este caso, pero creo que el ejemplo que puse debería aclarar lo que necesitas hacer.

aacampos3 commented 2 years ago

como se explica en # 243 (comentario) , lo que deberías obtener al usar Distrito.select(['nombre'])es una lista pero de instancias, no de tuplas, y lo que tiene que tener cada instancia es el valor correcto, es decir, si tu base de datos tiene 2 convencional con nombre Mario y Roberto, deberías obtener una lista con 2 instancias de Convencionales, cada una con el nombre cargado. Es decir podrías hacer:

convencional  =  Convencional . seleccionar ([ 'nombre' ])
  para  conv  en  convencionales :
      print ( conv . nombre )

y debería entregar

Mario
Roberto

no entiendo bien a lo que te refieres con sanitizar en este caso, pero creo que el ejemplo que puse debería aclarar lo que necesitas hacer.

Muchas gracias, me refería que tengo que colocar, con el ejemplo anterior algo como "SELECT" + lista [0] + "...". donde lista [0] = 'nombre'. Por lo que no sanitizaría lista [0] ¿O se puede colocar de esa manera?

rjherrera commented 2 years ago

ah ya, sí, efectivamente deberías prevenir inyecciones SQL. No tiene que ser muy sofisticado pero si lo dejas así con esos +, es muy simple hacer una inyección. Con algo simple que prevenga los casos típicos de inyección que se vieron en clases, está bien.

aacampos3 commented 2 years ago

ah ya, sí, efectivamente deberías prevenir inyecciones SQL. No tiene que ser muy sofisticado pero si lo dejas así con esos +, es muy simple hacer una inyección. Con algo simple que prevenga los casos típicos de inyección que se vieron en clases, está bien.

Muchas gracias, pero esa es mi duda porque al prevenir inyecciones como vimos en clase, al imprimir cur.fetchall() obtenía esta respuesta [('nombre',), ('nombre',), ('nombre',)].Utilicé la forma de la issue #234, es decir, en este ejemplo, :nombre

rjherrera commented 2 years ago

te cacho, creo que el uso que estás intentando darle a esa forma de sanitización no es el que se espera. Eso funciona bien cuando lo pasas como parámetro para un where, por ejemplo:

cur.execute("select * from distrito where name like :name", { 'name': '%d1%' })
print(cur.fetchall()) # [(3, 'd10'), (4, 'd11')]

Lo que tú estás intentando me imagino que es algo como select :name from ... y eso según entiendo no está soportado para la sanitización, porque lo que hace la sanitización es ponerle comillas a lo que escribas (entre otras cosas), de forma que se interprete como un string y no como código SQL, lo que hace que estés haciendo un select 'nombre' from ... y eso siempre va a dar tuplas con 'nombre' y no con el valor de la columna nombre.

Ahora, lo que puedes hacer es verificarlo a través de tu código y no directo con SQL, por ejemplo, revisar que lo que sea que estás intentando seleccionar, corresponda a columnas válidas comparando el string con los nombres de las columnas o algo así.

fernandosmither commented 2 years ago

Ahora, lo que puedes hacer es verificarlo a través de tu código y no directo con SQL, por ejemplo, revisar que lo que sea que estás intentando seleccionar, corresponda a columnas válidas comparando el string con los nombres de las columnas o algo así.

¿Es necesario que hagamos esto, o podemos asumir que al menos los placeholders no serán maliciosos, y nos enfocamos en sanitizar lo que se puede con execute?