如何在 BigQuery SQL 中安全地参数化表/列名称?

Posted

技术标签:

【中文标题】如何在 BigQuery SQL 中安全地参数化表/列名称?【英文标题】:How can I safely parameterize table/column names in BigQuery SQL? 【发布时间】:2020-05-18 15:54:16 【问题描述】:

我正在使用 python 的 BigQuery 客户端在 BigQuery 中创建并保持一些表的最新状态,这些表包含某些 firebase 事件的每日计数以及来自其他来源的数据(有时按国家/地区等分组)。使它们保持最新需要删除和替换过去几天的数据,因为 Firebase 事件的日期表可以在创建后更改(请参阅here 和 here)。我以这种方式使它们保持最新,以避免查询整个数据集,这在财务/计算上非常昂贵。

需要对许多表重复此删除和替换过程,因此我需要重用存储在文本文件中的一些查询。例如,从特定日期 (delete from x where event_date >= y) 开始删除表中的所有内容。但是因为 BigQuery 不允许对表名进行参数化(请参阅here),所以我必须为需要执行此操作的每个表复制这些查询文本文件。如果我想运行测试,我还必须复制上述对测试表的查询。

我基本上需要 psycopg2.sql 之类的东西来进行 bigquery,这样我就可以安全地参数化表和列名,同时避免使用 SQLi。实际上,我尝试通过调用 as_string() 方法并使用结果查询 BigQuery 来重新调整该模块的用途。但是生成的语法不匹配,我需要启动一个 postgres 连接来完成它(as_string() 需要一个游标/连接对象)。我还尝试了与sqlalchemy.text 类似的方法,但无济于事。所以我得出结论,我必须自己实现一些参数化表名的方法,或者使用 python 客户端库实现一些解决方法。关于我应该如何以不会导致 SQLi 的安全方式执行此操作的任何想法?无法详细说明,但不幸的是我无法将表存储在 postgres 或任何其他数据库中。

【问题讨论】:

您为什么担心 SLQi?你的代码会接收外部参数吗? 不,它不应该接收外部参数。我不是这些方面的专家,所以我不知道在服务器上存储一个用于此进程的 python 函数有多大风险,该服务器接受表名作为参数并仅使用字符串操作来进行查询。我的意思是你必须破解 ssh 才能访问服务器。你怎么看? 老实说,如果有人可以破解您的服务器,那么您遇到的最小问题就是通过此脚本执行 SQLi。入侵您的服务器的人可能会更改您的代码来做任何事情。我只是确保服务器安全性足够好。如果你真的觉得你应该处理 SQLi 的东西,我认为你可以尝试的一种方法是在继续之前用正则表达式检查你的参数。 是的,我认为黑客攻击服务器就是这种情况。但我不确定是否有人可以在没有完全访问服务器的情况下以某种方式调用脚本。我想我会采用正则表达式方法并在完成后发布答案。即使对于安全性而言,这不是完全必要的,但也可以向将使用我的代码的其他人报告格式错误。 我会发布一个答案来总结讨论。如果您觉得它更好地解释了解决方案,请随时添加您自己对问题的完整答案。 【参考方案1】:

正如 cmets 中所讨论的,在您的情况下避免使用 SQLi 的最佳选择是确保服务器的安全性。

如果您需要/想要在构建查询之前解析输入参数,我建议您使用REGEX 来检查输入字符串。 在 Python 中,您可以使用 re 库。

由于我不知道您的代码是如何工作的,您的数据集/表是如何组织的,而且我不知道您打算如何检查字符串是否是有效的来源,所以我创建了下面的基本示例来显示如何使用这个库检查字符串

import re

tests = ["your-dataset.your-table","(SELECT * FROM <another table>)", "dataset-09123.my-table-21112019"]

#Supposing that the input pattern is <dataset>.<table>
regex = re.compile("[a-zA-Z0-9-]+\.[a-zA-Z0-9-]+")

for t in tests:
    if(regex.fullmatch(t)):
        print("This source is ok")
    else:
        print("This source is not ok")

在此示例中,只有与配置 dataset.table 匹配的字符串(其中数据集和表都必须仅包含字母数字字符和破折号)才会被视为有效。

运行代码时,列表的第一个和第三个元素将被视为有效,而第二个(可能会更改您的整个查询)将被视为无效。

【讨论】:

以上是关于如何在 BigQuery SQL 中安全地参数化表/列名称?的主要内容,如果未能解决你的问题,请参考以下文章

如何保护带有参数化表名的查询不被注入

在 sqlplus 输入文件中参数化表名

SQL Server 动态行转列(参数化表名分组列行转列字段字段值)

我可以在准备好的语句中参数化表名吗?

我可以在准备好的语句中参数化表名吗?

SQL Server 动态行转列(参数化表名分组列行转列字段字段值)