在MySQL查询中有没有安全的方法来参数化数据库名称?
我正在写一个小的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的一部分。