如何将PostgreSQL查询追加到Python 3中的另一个查询并防止SQL注入?

How to append a query of PostgreSQL to another query in Python 3 and prevent SQL Injection?

我正在用Python 3编写一些脚本,需要从PostgreSQL数据库中读取数据。在一种情况下,我需要将一个查询追加到另一个查询,同时还要防止SQL注入。我尝试了其他方法(格式字符串,sql.SQL),但未成功。以下是我使用的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
data = {
    'id': 14,
    'user_id': (16, 'Administrator'),
    'from_date': datetime.datetime(2019, 1, 6, 5, 45, 15),
    'to_date': datetime.datetime(2020, 5, 3, 5, 45, 15),
    'state': 'to_be_review',
    'language': 'english',
}
query =" AND hr.unit_identification_code_id IN (%s)" % ','.join(map(str, uic_ids))
user_id = data.get('user_id') and data.get('user_id')[0] or 0
    if uic_ids:
        if data.get('state') != 'reject_submit':
            self._cr.execute(sql.SQL("""
                                    SELECT
                                        elh.id
                                    FROM
                                        employee_log_history elh
                                        LEFT JOIN
                                            hr_employee hr
                                            ON elh.hr_employee_id = hr.id
                                    WHERE
                                        elh.create_date >= %s
                                        AND elh.create_date <=%s
                                        AND elh.create_uid = %s
                                        AND elh.state = %s {}
                                   """
).format(sql.Identifier(query)), (data.get('from_date'), data.get('to_date'), user_id, data.get('state'),)  
                                )

但是当我运行脚本作为结果时,我得到的第一个查询用双引号引起以下错误:

1
2
psycopg2.ProgrammingError: syntax error at or near"" AND hr.unit_identification_code_id IN (33,34,35,36,37,38,39,40,41,42,49,47,60,61,63,64,62,43,46,58,59,50,57,48,44,51,52)""
LINE 13: ...                   AND elh.state = 'to_be_review'" AND hr.u...

现在我想知道是否可以执行此查询并阻止SQL注入,并在第二个查询中追加第一个查询?


sql.Identifier用于引用诸如表名或列名之类的标识符,而不用于适应SQL块。若要执行所需的操作,请使用sql.SQL。

这是一个简化的示例,在WHERE子句中添加了附加条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import psycopg2
from psycopg2 import sql

conn = psycopg2.connect(database='test')
cur = conn.cursor()

stmt1 ="SELECT name, password FROM users WHERE name = %s"
stmt2 = ' AND {} = %s'

composed = sql.SQL(stmt2).format('password')

print(composed)
Composed([SQL(' AND '), Identifier('password'), SQL(' = %s')])

print(repr(composed.as_string(cur)))
' AND"password" = %s'

cur.mogrify(stmt1 + composed.as_string(cur), ('Alice', 'secret'))
b'SELECT name, password FROM users WHERE name = \'Alice\' AND"password" = \'secret\''

混合字符串(stmt)和对象(composed)感觉有些古怪。您可能希望在代码中一致地使用对象,但这取决于您。