Fournir un mot de passe pour boucler MySQL
-
03-07-2019 - |
Question
Salutations.
J'ai écrit un petit script python qui appelle MySQL dans un sous-processus. [Oui, je sais que la bonne approche consiste à utiliser MySQLdb, mais sa compilation sous OS X Leopard est pénible et probablement plus pénible si je souhaite utiliser le script sur des ordinateurs d'architectures différentes.] La technique de sous-processus fonctionne, à condition que Je fournis le mot de passe dans la commande qui lance le processus; cependant, cela signifie que les autres utilisateurs de la machine pourraient voir le mot de passe.
Le code original que j'ai écrit est visible ici .
Cette variante ci-dessous est très similaire, même si je vais omettre la routine de test pour la raccourcir:
#!/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
Je soupçonne que l'invite de mot de passe MySQL n'est pas réellement sur stdout (ou stderr), bien que je ne sache pas comment cela pourrait être ou si cela signifie que je pourrais le piéger.
J'ai d'abord essayé de lire la sortie avant de fournir un mot de passe, mais cela n'a pas fonctionné. J'ai aussi essayé de passer le mot de passe
Encore une fois, si je fournis le mot de passe sur la ligne de commande (et ne dispose donc d'aucun code entre les fonctions "Popen" et "communiquer"), ma fonction encapsulée fonctionne.
Deux nouvelles pensées, des mois plus lents:
-
L'utilisation de pexpect me permettrait de fournir un mot de passe. Il simule un tty et obtient toutes les sorties, même celles qui contournent stdout et stderr.
-
Il existe un projet appelé Connecteur MySQL / Python , qui permet de fournir une bibliothèque python pure pour accéder à MySQL, sans avoir à compiler de code C.
La solution
Vous pouvez simplement créer un fichier my.cnf et y indiquer la commande mysql. Évidemment, vous voudrez protéger ce fichier avec permissions / acls. Mais il ne devrait pas être vraiment plus / moins sûr d’avoir le mot de passe dans votre script python, ou la configuration de votre script python.
Vous feriez donc quelque chose comme
mysql_cmd_line = "/Applications/MAMP/Library/bin/mysql --defaults-file=credentials.cnf"
et votre configuration ressemblerait à ceci
[client]
host = localhost
user = root
password = password
socket = /var/run/mysqld/mysqld.sock
Autres conseils
La seule méthode sécurisée consiste à utiliser un fichier cnf MySQL comme l’indique l’une des autres affiches. Vous pouvez également passer une variable env MYSQL_PWD, mais cela n’est pas sûr non plus: http://dev.mysql.com/doc/refman/5.0/fr/password-security.html
Alternativement, vous pouvez communiquer avec la base de données à l'aide d'un fichier de socket Unix et, avec quelques ajustements, vous pouvez contrôler les autorisations au niveau de l'ID utilisateur.
Encore mieux, vous pouvez utiliser la pile gratuite BitNami DjangoStack qui a pré-compilé Python et MySQLDB pour OS X (et Windows et Linux) http://bitnami.org/stacks
Il s’agit peut-être d’une fonctionnalité Windows / SQL Server, mais pouvez-vous utiliser une connexion sécurisée (c’est-à-dire utiliser votre identifiant / mot de passe du système d’exploitation pour accéder à la base de données)? Il peut y avoir un équivalent de Mac OS X pour MySQL.
Ou vous devrez peut-être simplement configurer votre base de données pour utiliser le nom d'utilisateur et le mot de passe du système d'exploitation, de sorte que vous n'ayez pas besoin de les conserver dans votre code.
En tout cas, juste une idée.
Essayez ceci:
process.stdin.write(mysql_password + "\n")
process.communicate()
(stdout, stderr) = process.communicate( sql_statement )
process.stdin.close()
return stdout
Appelez communic () pour forcer l’envoi de ce que vous venez d’écrire dans le tampon. En outre, il est bon de fermer stdin lorsque vous avez terminé.