【问题标题】:Django Raw Query with params on Table Column (SQL Injection)带有表列参数的 Django 原始查询(SQL 注入)
【发布时间】:2017-10-10 14:02:27
【问题描述】:

我有一个不寻常的场景,但除了我的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})

【问题讨论】:

  • 允许用户指定模式元素(而不是查询值)通常是使用字符串连接的原因,即使我们都经常被告知“永远不要这样做”。好消息是模式元素的超集是有限的。因此,您实际上不必包含未转义的用户输入。您可以根据已知的模式元素(硬编码或从数据库中动态查询)创建“有效”用户输入列表,将用户输入与该列表进行比较,如果找到匹配项,则将该匹配值连接到原始 SQL。
  • 这是一个好主意,我实际上可以用一个简单的正则表达式来实现。
  • 哦,如果这就是你要找的东西,那么我可以把它写下来作为答案。

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


【解决方案1】:

与任何潜在的 SQL 注入一样,小心

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

要在查询中动态包含架构元素,通常必须使用字符串连接。这正是我们都被告知不要使用 SQL 查询做的事情。

但好消息是您不必使用实际的用户输入。这是因为,虽然可能的查询值是无限的,但可能的有效模式元素 的超集是相当有限的。因此,您可以根据该超集验证用户的输入。

例如,考虑以下过程:

  1. 用户输入一个值作为列名。
  2. 代码将该值(原始字符串比较)与已知可能值的列表进行比较。 (此列表可以是硬编码的,也可以从数据库架构中动态获取。)
  3. 如果未找到匹配项,则返回错误。
  4. 如果找到匹配项,则直接在 SQL 查询中使用匹配的已知值。

因此,作为程序员,您所使用的只是您在代码中放入的字符串。这和自己写 SQL 是一样的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 感谢您的回复,我会对此表示赞同。我正在使用 postgres 扩展 timescaledb,我需要在未来包含 time_bucket(与 date_trunc 非常相似)所以我想(但我还没有到那一点)我需要坚持使用 raw 选项。
    • 您也许可以注释 time_bucket 而不是使用raw()。请参阅docs on expressions
    • 我尝试在这里解决这个问题:stackoverflow.com/questions/46688158/…
    猜你喜欢
    • 1970-01-01
    • 2015-11-21
    • 2012-03-16
    • 1970-01-01
    • 2013-04-17
    • 2012-03-13
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多