Table 列上带有参数的 Django 原始查询(SQL 注入)
Django Raw Query with params on Table Column (SQL Injection)
我有一个不寻常的场景,但除了我的 sql
参数之外,我还需要让用户 / API 定义 table 列名称。 params
我的问题是查询结果为:
SELECT device_id, time, 's0' ...
而不是
SELECT device_id, time, s0 ...
还有其他方法可以通过 raw
实现吗?还是我需要自己转义该列?
queryset = Measurement.objects.raw(
'''
SELECT device_id, time, %(sensor)s FROM measurements
WHERE device_id=%(device_id)s AND time >= to_timestamp(%(start)s) AND time <= to_timestamp(%(end)s)
ORDER BY time ASC;
''', {'device_id': device_id, 'sensor': sensor, 'start': start, 'end': end})
您发布的示例查询似乎不需要 raw()
。我认为以下查询集非常相似。
measurements = Measurement.objects.filter(
device_id=device_id,
to_timestamp__gte=start,
to_timestamp__lte,
).order_by('time')
for measurement in measurements:
print(getattr(measurement, sensor)
如果您需要优化并避免加载其他字段,您可以使用values()
或only()
。
对于任何可能的 SQL 注入,要小心。
但从本质上讲,这是一个相当普遍的问题,并且有一个相当安全的解决方案。一般来说,问题是查询参数 "the right way" 用于处理查询值,但它们不是为架构元素设计的。
要在查询中动态包含架构元素,通常必须求助于字符串连接。这正是我们都被告知不要处理 SQL 查询的事情。
但这里的好消息是您不必使用实际的用户输入。这是因为,虽然可能的查询值是无限的,但可能的 有效模式元素 的超集是非常有限的。因此,您可以根据该超集验证用户的输入。
例如,考虑以下过程:
- 用户输入一个值作为列名。
- 代码将该值(原始字符串比较)与已知可能值列表进行比较。 (这个列表可以是硬编码的,也可以从数据库模式中动态获取。)
- 如果找不到匹配项,return 出错。
- 如果找到匹配项,则直接在 SQL 查询中使用匹配的已知值。
因此,您所使用的只是您作为程序员放入代码中的字符串。无论如何,这与自己编写 SQL 相同。
我有一个不寻常的场景,但除了我的 sql
参数之外,我还需要让用户 / API 定义 table 列名称。 params
我的问题是查询结果为:
SELECT device_id, time, 's0' ...
而不是
SELECT device_id, time, s0 ...
还有其他方法可以通过 raw
实现吗?还是我需要自己转义该列?
queryset = Measurement.objects.raw(
'''
SELECT device_id, time, %(sensor)s FROM measurements
WHERE device_id=%(device_id)s AND time >= to_timestamp(%(start)s) AND time <= to_timestamp(%(end)s)
ORDER BY time ASC;
''', {'device_id': device_id, 'sensor': sensor, 'start': start, 'end': end})
您发布的示例查询似乎不需要 raw()
。我认为以下查询集非常相似。
measurements = Measurement.objects.filter(
device_id=device_id,
to_timestamp__gte=start,
to_timestamp__lte,
).order_by('time')
for measurement in measurements:
print(getattr(measurement, sensor)
如果您需要优化并避免加载其他字段,您可以使用values()
或only()
。
对于任何可能的 SQL 注入,要小心。
但从本质上讲,这是一个相当普遍的问题,并且有一个相当安全的解决方案。一般来说,问题是查询参数 "the right way" 用于处理查询值,但它们不是为架构元素设计的。
要在查询中动态包含架构元素,通常必须求助于字符串连接。这正是我们都被告知不要处理 SQL 查询的事情。
但这里的好消息是您不必使用实际的用户输入。这是因为,虽然可能的查询值是无限的,但可能的 有效模式元素 的超集是非常有限的。因此,您可以根据该超集验证用户的输入。
例如,考虑以下过程:
- 用户输入一个值作为列名。
- 代码将该值(原始字符串比较)与已知可能值列表进行比较。 (这个列表可以是硬编码的,也可以从数据库模式中动态获取。)
- 如果找不到匹配项,return 出错。
- 如果找到匹配项,则直接在 SQL 查询中使用匹配的已知值。
因此,您所使用的只是您作为程序员放入代码中的字符串。无论如何,这与自己编写 SQL 相同。