2012-07-18 9 views

risposta

17

Uso SQLAlchemy per le query dirette in qualsiasi momento.

Vantaggio principale: offre la migliore protezione contro gli attacchi SQL injection. SQLAlchemy fa la cosa giusta a prescindere dai parametri che ci passi.

Trovo che funzioni miracoli per regolare l'SQL generato in base alle condizioni. Visualizzazione di un set di risultati con più controlli filtro sopra di esso? Costruisci la tua query in un insieme di costrutti if/elif/else e sai che il tuo SQL sarà ancora in oro.

Ecco un estratto da un certo codice in diretta (versione precedente SA, quindi la sintassi potrebbero differire un po '):

# Pull start and end dates from form 
# ... 
# Build a constraint if `start` and/or `end` have been set. 
created = None 
if start and end: 
    created = sa.sql.between(msg.c.create_time_stamp, 
     start.replace(hour=0, minute=0, second=0), 
     end.replace(hour=23, minute=59, second=59)) 
elif start: 
    created = (msg.c.create_time_stamp >= 
       start.replace(hour=0, minute=0, second=0)) 
elif end: 
    created = (msg.c.create_time_stamp <= 
       end.replace(hour=23, minute=59, second=59)) 

# More complex `from_` object built here, elided for example 
# [...] 
# Final query build 
query = sa.select([unit.c.eli_uid], from_obj=[from_]) 
query = query.column(count(msg.c.id).label('sent')) 
query = query.where(current_store) 
if created: 
    query = query.where(created) 

Il codice in cui questo viene da è molto più complesso, ma ho voluto evidenziare la codice dell'intervallo di date qui. Se dovessi costruire l'SQL usando la formattazione di stringhe, probabilmente avrei introdotto un foro di iniezione SQL da qualche parte, dato che è molto più facile dimenticare di citare valori.

1

Dopo aver lavorato a un mio piccolo progetto, ho deciso di provare a utilizzare solo MySQLDB, senza SQL Alchemy.

Funziona bene ed è abbastanza facile da usare, ecco un esempio (ho creato una piccola classe che gestisce tutto il lavoro alla base di dati)

import MySQLdb 
from MySQLdb.cursors import DictCursor 

class DatabaseBridge(): 
    def __init__(self, *args, **kwargs): 
     kwargs['cursorclass'] = DictCursor 
     self.cnx = MySQLdb.connect (**kwargs) 
     self.cnx.autocommit(True) 
     self.cursor = self.cnx.cursor() 

    def query_all(self, query, *args): 
     self.cursor.execute(query, *args) 
     return self.cursor.fetchall() 

    def find_unique(self, query, *args): 
     rows = self.query_all(query, *args); 
     if len(rows) == 1: 
      return rows[0] 

     return None 

    def execute(self, query, params): 
     self.cursor.execute(query, params) 
     return self.cursor.rowcount 

    def get_last_id(self): 
     return self.cnx.insert_id() 

    def close(self): 
     self.cursor.close() 
     self.cnx.close() 

database = DatabaseBridge(**{ 
     'user': 'user', 
     'passwd': 'password', 
     'db': 'my_db' 
    }) 

rows = database.query_all("SELECT id, name, email FROM users WHERE is_active = %s AND project = %s", (1, "My First Project")) 

(si tratta di un esempio di muto).

Funziona come un fascino MA si deve prendere in considerazione questi:

  • multithreading non è supportato! Va bene se non si lavora con multiprocessing da Python.
  • Non avrete tutti i vantaggi di SQLAlchemy (wrapper di Database to Class (modello), generazione di query (selezionare, dove, order_by, ecc.)). Questo è il punto chiave su come si desidera lavorare con il proprio database.

Ma d'altra parte, e come SQLAlchemy, c'è protezioni agains't attacchi di SQL injection:

Una query di base sarebbe stato così:

cursor.execute("SELECT * FROM users WHERE data = %s" % "Some value") # THIS IS DANGEROUS 

Ma si dovrebbe fare :

cursor.execute("SELECT * FROM users WHERE data = %s", "Some value") # This is secure! 

Hai visto la differenza? Leggi di nuovo;)

La differenza è che ho sostituito %, per ,: passiamo gli argomenti come ... argomenti all'esecuzione, e questi sono sfuggiti. Quando si utilizza %, gli argomenti non sono sfuggiti, abilitando gli attacchi SQL Injection!

L'ultima parola è che dipende dal vostro utilizzo e da ciò che intendete fare con il vostro progetto. Per me, SQLAlchemy era in overkill (è uno script di shell di base!), Quindi MysqlDB era perfetto.

Problemi correlati