2011-06-28 42 views
32

¿Cuáles son las mejores prácticas para mitigar los ataques de inyección SQL al usar SQLAlchemy?SQLAlchemy + SQL Injection

+24

El uso de SQLAlchemy * es * la mejor práctica. :-) –

Respuesta

31

Si tiene alguna caracteres "especiales" (como punto y coma o apóstrofes) en sus datos, van a ser citado automáticamente para usted por el objeto SQLEngine, por lo que no tiene que preocuparse por Citando Esto también significa que a menos que evites deliberadamente Mecanismos de cotización de SQLAlchemy, ataques de inyección SQL son básicamente imposible.

[por http://www.rmunn.com/sqlalchemy-tutorial/tutorial.html]

+16

La respuesta dice que la cita proviene de "la" documentación, cuando no: parece provenir de [un tutorial] (http://www.rmunn.com/sqlalchemy-tutorial/tutorial.html) no asociado con SQLAlchemy. En segundo lugar, la cita está en el contexto de parte de la API de SQLAlchemy que manejará correctamente el escape, utilizando un ejemplo que maneja el escape. Sin embargo, aún puede usar 'execute()' u otros datos literales que NO serán escapados por SQLAlchemy. Sí, en la mayoría de los casos, SQLAlchemy se escapará automáticamente, pero si está utilizando literales o SQL sin procesar, puede dispararse en el pie. –

51

tldr: Evitar SQL prima tanto como sea posible.

La respuesta aceptada es floja e incorrecta. El método de filtro acepta SQL sin procesar, y si se usa de esa manera, es totalmente susceptible a los ataques de inyección de SQL. Por ejemplo, si se aceptara un valor de una URL y combinarlo con SQL prima en el filtro, que está abierta al ataque:

session.query(MyClass).filter("foo={}".format(getArgs['val']))

utilizando el código anterior y la URL a continuación, que sería Inyectando SQL en tu declaración de filtro. El código anterior devolverá todas las filas en su base de datos.

http://domain.com/?val=2%20or%201%20=%201

+4

"a menos que deliberadamente eluda los mecanismos de cotización de SQLAlchemy ..."Sí, al ingresar raw sql está eludiendo deliberadamente ese mecanismo de cotización. Así que no, la respuesta anterior no es incorrecta. – Johnston

+12

No estoy de acuerdo. Que se pueda pasar sql crudo al método de filtro es parte de sqlalchemy, no un truco final ... por lo que vale la pena señalar aquí como algo a tener en cuenta. – Mike

+2

Si tengo que aceptar la entrada del usuario para un filtro, ¿cuál es la forma correcta de asegurarse de que el usuario no ingrese SQL sin formato para eliminar tablas o cualquier otro comportamiento inesperado? –

3

Para añadir a @Tendrid answer. Hice una pequeña investigación usando un enfoque ingenuo y callado. El método filter tiene *criterion como argumento, varios otros métodos ORM Query tienen un argumento similar.

En caso de filter, el método *criterion termina en _literal_as_text, que en caso de cadena lo marca como sql seguro (corríjalo si me equivoco). Por lo tanto, lo hace inseguro.

Aquí es resultado de la investigación ORM Query class método con *criterion argumento:

filter - uses _literal_as_text (NOT SAFE) 
having - uses _literal_as_text (NOT SAFE) 

distinct - uses _literal_as_label_reference (NOT SAFE) 
group_by - uses _literal_as_label_reference (NOT SAFE) 
order_by - uses _literal_as_label_reference (NOT SAFE) 

join  - uses model attributes to resolve relation (SAFE) 

Ejemplos de posibles missuses método (mantenerlo simple, la cadena de formato se omite):

db.session.query(User.login).group_by('login').having('count(id) > 4; select name from roles').all() 
db.session.query(User.login).distinct('name) name from roles /*').order_by('*/').all() 
db.session.query(User.login).order_by('users_login; select name from roles').all() 
db.session.query(User.login).group_by('login union select name from roles').all() 

Nota que estos métodos solo son inseguros si se pasa el literal de cadena.