在MySQL查询中有没有安全的方法来参数化数据库名称?

2 投票
2 回答
1391 浏览
提问于 2025-04-16 21:18

我正在写一个小的Python脚本,目的是帮助我自动创建MySQL数据库和相关的账户,用于我的个人项目。这个脚本里有一个功能,它接收数据库名称作为字符串,然后去创建这个数据库。

def createDB(dbConn, dbName):
    import MySQLdb
    c = dbConn.cursor()
    query = """CREATE DATABASE %s;""";
    c.execute(query, (dbName,))

这个功能不管用,因为MySQL的CREATE DATABASE要求数据库名称不能加引号,比如说:

  CREATE DATAbASE test_db

但是我写的代码试图安全地把用户提供的数据库名称插入到查询中,结果却变成了:

  CREATE DATABASE 'test_db'

然后你会看到“在test附近你的MySQL语法有问题”。

即使这是为了个人使用,我也不想直接把用户提供的字符串插入到任何查询中。这是我的原则。有没有安全的方法可以在Python(或任何语言)中把用户提供的数据库名称插入到MySQL查询中,确保像test_db; DROP some_other_db;这样的用户输入会被拒绝或正确处理呢?

2 个回答

5

数据库名称(还有列名和表名)并不是数据值,所以不应该用占位符来表示。想要这样做通常是个坏主意;只有数据库管理员(DBA)才能执行 create database 这个操作,因为这需要一些特殊的权限。大多数应用程序都需要数据库管理员来创建数据库,然后再把创建好的数据库作为参数传给 dbapi.Connection。

如果你真的确定需要这样做,并且你信任输入的来源,同时也检查过输入中没有无效字符,那么你可以在 Python 中直接进行替换,像这样:

def createDB(dbConn, dbName):
    c = dbConn.cursor()
    query = """CREATE DATABASE %s;""" % dbName
    c.execute(query)
2

经过一些调查,发现phpmyadmin使用反引号来引用数据库、表和列的名称。它们的做法是这样的:

$sql_query = 'CREATE DATABASE ' . PMA_backquote($new_db);  

在上面的错误情况下,这样做会产生类似于

CREATE DATABASE `test_db; DROP some_other_db`;

当然,输入字符串中的任何反引号都需要进行转义。根据phpmyadmin的代码,转义的方法是把所有单个反引号替换成双反引号。不过,我找不到任何地方确认这个做法是正确的。

我还注意到,网上有说反引号并不是标准SQL的一部分。

撰写回答