使用 psycopg cur.execute 创建 postgres 模式

Creating postgres schemas using psycopg cur.execute

我的 python 应用程序允许用户创建他们的命名模式。我需要一种方法来保护应用程序免受 sql 注入。

要执行的SQL读取

CREATE SCHEMA schema_name AUTHORIZATION user_name;

psycopg 文档(通常)建议像这样传递参数来执行

conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()
query = 'CREATE SCHEMA IF NOT EXISTS %s AUTHORIZATION %s;'
params = ('schema_name', 'user_name')
cur.execute(query, params)

但这会导致使用单引号的查询失败:

CREATE SCHEMA 'schema_name' AUTHORIZATION 'user_name';
> fail

有没有办法删除引号,或者我应该只接受从架构名称中删除非字母数字字符并收工?后者看起来有点丑,但应该仍然有效。

要传递标识符,请使用 AsIs。但这暴露了 SQL 注入:

import psycopg2
from psycopg2.extensions import AsIs

conn = psycopg2.connect(database='cpn')
cursor = conn.cursor()
query = """CREATE SCHEMA %s AUTHORIZATION %s;"""
param = (AsIs('u1'), AsIs('u1; select * from user_table'))
print cursor.mogrify(query, param)

输出:

CREATE SCHEMA u1 AUTHORIZATION u1; select * from user_table;

自 psycopg2 >= 2.7 起,psycopg2.sql 可用于编写动态语句,这也可防止 SQL 注入。

这是一个可能有用的样板文件。我使用了环境变量,但你可以使用 .conf 或任何你喜欢的。

将您的连接变量存储在 .env 文件中:

db_host = "localhost"
db_port = "5432"
db_database = "postgres"
db_user = "postgres"
db_password = "postgres"
db_schema = "schema2"

在您的 app.py 中加载参数并将它们分配给变量,然后在需要的地方使用变量:

import psychopg2
from dotenv import load_dotenv
import database

# Load your environment variables here:
load_dotenv()

db_host = os.environ["db_host"]
db_port = os.environ["db_port"]
db_database = os.environ["db_database"]
db_user = os.environ["db_user"]
db_password = os.environ["db_password"]
db_schema = os.environ["db_schema"]

# Build Connection:
connection = psycopg2.connect(host=db_host, 
                              port=db_port, 
                              database=db_database, 
                              user=db_user, 
                              password=db_password
                              )

# Build Query Strings:
CREATE_SCHEMA = f"CREATE SCHEMA IF NOT EXISTS {schema};"
CREATE_TABLE1 = f"CREATE TABLE IF NOT EXISTS {schema}.table1 (...);"
CREATE_TABLE2 = f"CREATE TABLE IF NOT EXISTS {schema}.table2 (...);"


# Create Schema and Tables:
with connection:
    with connection.cursor() as cursor:
        cursor.execute(CREATE_SCHEMA)
        cursor.execute(CREATE_TABLE1)
        cursor.execute(CREATE_TABLE2)