Django Raw查询表列上的参数(SQL注入)

时间:2017-10-10 14:02:28

标签: python django postgresql django-rest-framework sql-injection

我有一个不寻常的场景,但除了我的sql参数之外,我还需要让用户/ API定义表列名。我对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})

2 个答案:

答案 0 :(得分:1)

与SQL注入的任何可能性一样,小心

但基本上这是一个相当普遍的问题,有一个相当安全的解决方案。一般来说,问题是查询参数是处理查询值的“正确方法”,但它们不是为模式元素设计的。

要在查询中动态包含架构元素,通常必须求助于字符串连接。我们都被告知不要使用SQL查询。

但这里的好消息是你不必使用实际的用户输入。这是因为,尽管可能的查询值是无限的,但可能的有效模式元素的超集是非常有限的。因此,您可以针对该超集验证用户的输入。

例如,请考虑以下过程:

  1. 用户输入一个值作为列名。
  2. 代码将该值(原始字符串比较)与已知可能值的列表进行比较。 (此列表可以是硬编码的,也可以从数据库模式中动态获取。)
  3. 如果未找到匹配项,请返回错误。
  4. 如果找到匹配项,请直接在SQL查询中使用匹配的已知值。
  5. 所以你所使用的只是你作为程序员放入代码的字符串。这与自己编写SQL无关。

答案 1 :(得分:0)

对于您发布的示例查询,您似乎不需要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()