python - 以安全的方式从字典数据创建表
问题描述
我有一个问题,我有一个字典列表,例如以下数据:
columns = [{
'name': 'column1',
'type': 'varchar'
},
{
'name': 'column2',
'type': 'decimal'
},
.
.
.
]
从该列表中,我需要根据列表中包含列名称和类型的每个字典动态创建一个 CREATE TABLE 语句,并使用 psycopg2 适配器在 PostgreSQL 数据库上执行它。
我设法做到了:
columns = "(" + ",\n".join(["{} {}".format(col['name'], col['type']) for col in columns]) + ")"
cursor.execute("CREATE TABLE some_table_name\n {}".format(columns))
但是这种解决方案容易受到 SQL 注入的影响。我试图用 psycopg2 的 sql 模块做同样的事情,但没有运气。总是出现语法错误,因为它将类型括在引号中。
有什么方法可以安全地完成吗?
解决方案
您可以使用AsIs来获取添加的列类型不带引号:
import psycopg2
from psycopg2.extensions import AsIs
import psycopg2.sql as sql
conn = psycopg2.connect("dbname=mf port=5959 host=localhost user=mf_usr")
columns = [{
'name': "column1",
'type': "varchar"
},
{
'name': "column2",
'type': "decimal"
}]
# create a dict, so we can use dict placeholders in the CREATE TABLE query.
column_dict = {c['name']: AsIs(c['type']) for c in columns}
createSQL = sql.SQL("CREATE TABLE some_table_name\n ({columns})").format(
columns = sql.SQL(',').join(
sql.SQL(' ').join([sql.Identifier(col), sql.Placeholder(col)]) for col in column_dict)
)
print(createSQL.as_string(conn))
cur = conn.cursor()
cur.execute(createSQL, column_dict)
cur.execute("insert into some_table_name (column1) VALUES ('foo')")
cur.execute("select * FROM some_table_name")
print('Result: ', cur.fetchall())
输出:
CREATE TABLE some_table_name
("column1" %(column1)s,"column2" %(column2)s)
Result: [('foo', None)]
注意:
psycopg2.sql
对 SQL 注入是安全的,AsIs
可能不是。测试使用'type': "varchar; DROP TABLE foo"
导致 Postgres 语法错误:
b'CREATE TABLE some_table_name\n ("column1" varchar; DROP TABLE foo,"column2" decimal)'
Traceback (most recent call last):
File "pct.py", line 28, in <module>
cur.execute(createSQL, column_dict)
psycopg2.errors.SyntaxError: syntax error at or near ";"
LINE 2: ("column1" varchar; DROP TABLE foo,"column2" decimal)
推荐阅读
- javascript - 使用 Vue.js 存储和使用用户数据的最佳实践
- react-native - 反应原生动画未运行
- reactjs - 从 Firebase 存储播放音频文件可以在本地工作,但不能在已部署的应用程序上工作
- c++ - Google Mock 一个返回 void 但采用 std::unique_ptr 的方法
- reactjs - 有没有办法在 NextJS 路由中使用多个参数?
- javascript - 如何创建倒数计时器关联至 graytimes.js
- javascript - 更改带有动画的按钮图标
- c - 不支持#pragma STDC FENV_ACCESS ON 如何影响__STDC_IEC_559__ 和__STDC__?
- go - 为什么时间转换取决于日期?
- mongodb - 在 mongo 中查找嵌套字段与值匹配的示例文档