【问题标题】:Proper use of Psycopg2 SQL module正确使用 Psycopg2 SQL 模块
【发布时间】:2020-08-29 20:05:37
【问题描述】:

由于 Maurice Meyer 让我意识到的语法错误而编辑了问题

我需要保护应用免受 SQL 注入,因此请使用 Psycopg2 中的 sql 模块。这会生成一个有效的查询:

conn = get_db()
cur = conn.cursor()
with open(fp, 'r') as f:
    query = sql.SQL("COPY parts ({fields}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)").format(
        fields = sql.SQL(',').join(sql.Identifier(col) for col in cols))
    cur.copy_expert(query, f)

但是我想知道这是否是正确的解决方案。由于生成的查询是:

print(query.as_string(conn))
>>> COPY parts ("asin","name","t_id","supp_pid","acq_price","deposit","ean","m_pid") FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)

但根据Postgresql docs,标识符应该不加引号。 为什么它仍然有效?

【问题讨论】:

    标签: python sql-injection psycopg2 composable


    【解决方案1】:

    括号没有正确闭合。您在字符串上使用format,而不是在 SQL 对象上:

    with open(fp, 'r') as f:
        _sql = "COPY parts ({}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)"
        query = sql.SQL(_sql).format(
            sql.SQL(',').join(sql.Identifier(col) for col in cols)
        )
        print(query.as_string(conn))
        cur.copy_expert(query, f)
    

    输出:

    COPY parts ("firstname","lastname") FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)
    Traceback (most recent call last):
      File "pg2.py", line 14, in <module>
        cur.copy_expert(query, f)
    psycopg2.errors.UndefinedTable: relation "parts" does not exist
    

    注意,关于带引号的标识符:

    假设您有一个包含空格的列名,那么您需要引用它们才能使用它们。因此允许使用 引号,同样的行为适用于 postgres 控制台。

    >>> cur.execute("""select firstname, "desc ription" from users2 where lastname = 'bar'""")
    >>> print(cur.fetchone())
    RealDictRow([('firstname', 'fo'), ('desc ription', 'baz')])
    

    【讨论】:

    • 谢谢!该行的那部分超出了我的编辑器视口,因此我错过了它。但是,返回的查询仍然具有引用的标识符,根据 Postgresql 文档,这些标识符的格式不正确 - 但它可以工作。我不明白。
    【解决方案2】:

    你有一个错字:

    sql.SQL("xxx".format(...))
    

    代替:

    sql.SQL("xxx").format(...)
                 ^ this (
    

    所以:

    query = sql.SQL("COPY parts ({fields}) FROM STDIN WITH (FORMAT CSV, DELIMITER ';', ENCODING UTF8)").format(
            fields = sql.SQL(',').join(sql.Identifier(col) for col in cols))
    

    【讨论】:

      猜你喜欢
      • 2022-01-07
      • 1970-01-01
      • 2019-02-18
      • 1970-01-01
      • 2015-10-24
      • 2017-08-14
      • 2015-10-07
      • 1970-01-01
      • 2021-08-24
      相关资源
      最近更新 更多