Fornire password per MySQL concluso
-
03-07-2019 - |
Domanda
Saluti.
Ho scritto un piccolo script Python che chiama MySQL in un sottoprocesso. [Sì, so che l'approccio giusto è usare MySQLdb, ma compilarlo sotto OS X Leopard è una seccatura, e probabilmente più doloroso se volessi usare lo script su computer di diverse architetture.] La tecnica del sottoprocesso funziona, a condizione che Fornisco la password nel comando che avvia il processo; tuttavia, ciò significa che altri utenti sulla macchina potrebbero vedere la password.
Il codice originale che ho scritto può essere visto qui .
Questa variante di seguito è molto simile, anche se ometterò la routine di test per renderla più breve:
#!/usr/bin/env python
from subprocess import Popen, PIPE
# Set the command you need to connect to your database
mysql_cmd_line = "/Applications/MAMP/Library/bin/mysql -u root -p"
mysql_password = "root"
def RunSqlCommand(sql_statement, database=None):
"""Pass in the SQL statement that you would like executed.
Optionally, specify a database to operate on. Returns the result."""
command_list = mysql_cmd_line.split()
if database:
command_list.append(database)
# Run mysql in a subprocess
process = Popen(command_list, stdin=PIPE, stdout=PIPE,
stderr=PIPE, close_fds=True)
#print "Asking for output"
#needs_pw = process.stdout.readline()
#print "Got: " + needs_pw
# pass it in the password
process.stdin.write(mysql_password + "\n")
# pass it our commands, and get the results
#(stdout, stderr) = process.communicate( mysql_password + "\n" + sql_statement)
(stdout, stderr) = process.communicate( sql_statement )
return stdout
Sono sospettoso che la richiesta della password di MySQL non sia effettivamente su stdout (o stderr), anche se non so come potrebbe essere o se ciò significhi che potrei intrappolarlo.
Ho provato prima a leggere l'output, prima di fornire una password, ma non ha funzionato. Ho anche provato a passare la password
Ancora una volta, se fornisco la password sulla riga di comando (e quindi non ho un codice tra le funzioni "Popen" e "Comunicazione") la mia funzione "wrapped" funziona.
Due nuovi pensieri, mesi dopo:
-
L'uso di pexpect mi permetterebbe di fornire una password. Simula un tty e ottiene tutto l'output, anche quello che ignora stdout e stderr.
-
Esiste un progetto chiamato MySQL Connector / Python , in versione alpha, che consentirà di fornire una libreria Python pura per l'accesso a MySQL, senza la necessità di compilare alcun codice C.
Soluzione
Potresti semplicemente creare un file my.cnf e puntare a quello sul comando mysql. Ovviamente ti consigliamo di proteggere quel file con autorizzazioni / acls. Ma non dovrebbe essere davvero più / meno sicuro che avere la password nel tuo script Python o la configurazione per il tuo script Python.
Quindi faresti qualcosa del genere
mysql_cmd_line = "/Applications/MAMP/Library/bin/mysql --defaults-file=credentials.cnf"
e la tua configurazione sarebbe simile a questa
[client]
host = localhost
user = root
password = password
socket = /var/run/mysqld/mysqld.sock
Altri suggerimenti
L'unico metodo sicuro è usare un file cnf di MySQL come uno degli altri poster menzionati. Puoi anche passare una variabile env MYSQL_PWD, ma anche questa non è sicura: http://dev.mysql.com/doc/refman/5.0/en/password-security.html
In alternativa, puoi comunicare con il database usando un file socket Unix e con un po 'di modifica puoi controllare le autorizzazioni a livello di ID utente.
Ancora meglio, puoi usare lo stack gratuito BitNami DjangoStack con Python e MySQLDB precompilati per OS X (e Windows e Linux) http://bitnami.org/stacks
Potrebbe trattarsi di una funzionalità di Windows / SQL Server, ma potresti utilizzare una connessione sicura (ovvero utilizzare il tuo login / password del sistema operativo per accedere al DB)? Potrebbe esserci un equivalente di OS X per MySQL.
Oppure potresti aver solo bisogno di impostare il tuo DB per utilizzare il login e la password del SO in modo da non doverlo conservare nel tuo codice.
Comunque, solo un'idea.
Prova questo:
process.stdin.write(mysql_password + "\n")
process.communicate()
(stdout, stderr) = process.communicate( sql_statement )
process.stdin.close()
return stdout
Chiama communic () per forzare l'invio di ciò che hai appena scritto nel buffer. Inoltre, è utile chiudere stdin al termine.