如何避免在 Python 中注入 SQL 以对 SQL Server 进行 Upsert 查询?

How to avoid SQL Injection in Python for Upsert Query to SQL Server?

提问人:randomguy2443 提问时间:11/13/2022 最后编辑:randomguy2443 更新时间:11/14/2022 访问量:262

问:

我正在执行一个sql查询,我正在将变量传递到该查询中。在当前上下文中,我将参数值作为 f 字符串传递,但此查询容易受到 sql 注入的影响。我知道有一种方法可以使用存储过程并限制执行查询的用户的权限。但是,有没有办法避免走存储过程路线,也许可以修改此函数以防 SQL 注入?

I have the below query created to execute within a python app.

def sql_gen(tv, kv, join_kv, col_inst, val_inst, val_upd):
    sqlstmt =  f"""
  IF NOT EXISTS (
          SELECT *
          FROM {tv}
          WHERE {kv} = {join_kv}
          )
      INSERT {tv} (
      {col_inst}
      )
      VALUES (
      {val_inst}
      )
  ELSE
      UPDATE {tv}
      SET {val_upd}
      WHERE {kv} = {join_kv};
      """
    engine = create_engine(f"mssql+pymssql://{username}:{password}@{server}/{database}")
    connection = engine.raw_connection()
    cursor = connection.cursor()

    cursor.execute(sqlstmt)
    connection.commit()

    cursor.close()
python SQL注入

评论


答:

0赞 Amanzer 11/13/2022 #1

幸运的是,大多数数据库连接器都有查询参数,您可以在其中传递变量,而不是在查询中自己提供字符串来应对您提到的风险。 您可以在此处阅读更多相关信息: https://realpython.com/prevent-python-sql-injection/#understanding-python-sql-injection

例:

# Vulnerable
cursor.execute("SELECT admin FROM users WHERE username = '" + username + '");
# Safe
cursor.execute("SELECT admin FROM users WHERE username = %s'", (username, ));

0赞 Egret 11/14/2022 #2

正如 Amanzer 在他的回复中正确提到的那样,Python 具有安全传递参数的机制。

但是,查询中还有其他元素(表名和列名)不支持作为参数(绑定变量),因为 JDBC 不支持这些元素。

如果这些元素来自不受信任的来源(或将来可能来自不受信任的来源),则应确保验证这些元素。即使您确定,这是一个很好的编码实践。

有一些选项可以安全地执行此操作:

  • 应根据肯定验证来限制表和列 - 确保唯一允许的值是已授权的值

如果这是不可能的(因为这些是用户创建的?

  • 应确保表或列名限制 使用一组“安全”字符(字母数字和破折号、 下划线...
  • 您应该引用表名/列名 - 在对象两边添加双引号。如果这样做,则需要 小心验证名称中没有引号,并出错 或转义引号。您还需要注意添加引号 将使名称区分大小写。