【问题标题】:Supplying password to wrapped-up MySQL为包装好的 MySQL 提供密码
【发布时间】:2009-03-06 17:58:49
【问题描述】:

您好。

我编写了一个小 Python 脚本,在子进程中调用 MySQL。 [是的,我知道正确的方法是使用 MySQLdb,但在 OS X Leopard 下编译它很痛苦,如果我想在不同架构的计算机上使用该脚本,可能会更痛苦。] 子进程技术有效,前提是我在启动进程的命令中提供密码;但是,这意味着机器上的其他用户可以看到密码。

我写的原代码可以看here

下面的这个变体非常相似,虽然我会省略测试例程以使其更短:

#!/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

我怀疑 MySQL 密码提示实际上不在 stdout(或 stderr)上,尽管我不知道这是怎么回事,或者这是否意味着我可以捕获它。

在提供密码之前,我确实尝试过先读取输出,但它不起作用。我也试过传递密码

同样,如果我在命令行上提供密码(因此在“Popen”和“communicate”函数之间没有代码)我的包装函数可以工作。


两个新想法,几个月后:

  1. 使用pexpect 可以让我提供密码。它模拟一个 tty 并获取所有输出,即使是绕过 stdout 和 stderr 的输出。

  2. 有一个名为 MySQL Connector/Python 的项目处于早期 alpha 阶段,它将允许提供一个纯 Python 库来访问 MySQL,而无需您编译任何 C 代码。

【问题讨论】:

  • 在网上一些实验和进一步搜索之间,我确定mysql的客户端在读取密码时不使用stdin,而是直接访问tty。因此,再多的重定向标准输入都不起作用。
  • @deemer - 我以为是这样的。

标签: python mysql subprocess


【解决方案1】:

您可以简单地构建一个 my.cnf 文件并在 mysql 命令上指向该文件。显然,您需要使用权限/acls 来保护该文件。但它不应该比在你的 python 脚本中拥有密码或你的 python 脚本的配置更安全。

所以你会做类似的事情

mysql_cmd_line = "/Applications/MAMP/Library/bin/mysql --defaults-file=credentials.cnf"

你的配置看起来像这样

[client]
host     = localhost
user     = root
password = password
socket   = /var/run/mysqld/mysqld.sock

【讨论】:

  • 这就像一个魅力,只要我注释掉套接字行(以及当我用  socket = /Applications/MAMP/tmp/mysql/mysql.sock 替换它时,谢谢!跨度>
【解决方案2】:

唯一安全的方法是使用 MySQL cnf 文件,正如其他海报中提到的那样。你也可以传递一个 MYSQL_PWD 环境变量,但这也是不安全的:http://dev.mysql.com/doc/refman/5.0/en/password-security.html

或者,您可以使用 Unix 套接字文件与数据库通信,并稍作调整即可在用户 ID 级别控制权限。

更好的是,您可以使用免费的 BitNami 堆栈 DjangoStack,它为 OS X(以及 Windows 和 Linux)预编译了 Python 和 MySQLDB http://bitnami.org/stacks

【讨论】:

    【解决方案3】:

    这可能是 Windows / SQL Server 功能,但您可以使用受信任的连接(即使用您的操作系统登录名/密码访问数据库)吗? MySQL 可能有一个 OS X 等价物。

    或者您可能只需要设置您的数据库以使用操作系统登录名和密码,这样您就不需要将其保存在您的代码中。

    无论如何,只是一个想法。

    【讨论】:

      【解决方案4】:

      试试这个:

      process.stdin.write(mysql_password + "\n")
      process.communicate()
      (stdout, stderr) = process.communicate( sql_statement )
      process.stdin.close()
      
      return stdout
      

      调用communicate() 来强制发送你刚刚写入缓冲区的内容。另外,完成后最好关闭标准输入。

      【讨论】:

      • 谢谢。不过,恐怕它没有用。 MySql 似乎在要求用户输入,并且不会从脚本中接受它。至于关闭标准输入,是否将 close_fds=True 传递给 Popen 命令会解决这个问题?
      猜你喜欢
      • 2019-01-20
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 2013-08-02
      • 1970-01-01
      相关资源
      最近更新 更多