提问人:Bylaw 提问时间:11/17/2023 最后编辑:Bylaw 更新时间:11/17/2023 访问量:17
Dremio SQL 注入漏洞
Dremio SQL injection vulnerability
问:
我想通过使用 Dremio 的 Spring Java 应用程序查询包含 parquet 文件的 S3 存储。这些是具有用户给定参数的动态查询。
我使用 Apache Arrow SQl 驱动程序,只需使用以下属性实例化即可运行查询:JdbcTemplate
DataSource
driver-class-name: org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver
url: jdbc:arrow-flight-sql://localhost:32010/?useEncryption=false
username: user
password: pwd
对于 sql 字符串,我使用使用用户给定值格式化的字符串:
"SELECT * FROM "my-s3-storage".table t WHERE t.description = '%s';".formatted(userInput)
它运行良好,但毋庸置疑,它的 SQL 注入机会有多大。如果我尝试使用预准备语句:
String sql = "SELECT * FROM "my-s3-storage".table t WHERE t.description = ?"
jdbcTemplate.query(sql, ps -> ps.setString(1, userInput), rs -> {
//handling the result set
});
我收到以下错误:
cfjd.org.apache.arrow.flight.FlightRuntimeException: Cannot convert RexNode to equivalent Dremio expression. RexNode Class: org.apache.calcite.rex.RexDynamicParam, RexNode Digest: ?0
我在网上发现了模棱两可的信息。在一些论坛上可以找到 Dremio 不支持预处理语句的说法,但所有这些评论都已有好几年的历史了,甚至 Dremio 官方网站也有一篇文章推荐使用预处理语句。
据我所知,Dremio 在后台使用 ANSI SQL,我相信它支持准备好的语句。或者这是否取决于数据库引擎而不是方言?谁能确认 Dremio 仍然不可能?然后我就不再追究了。
如果是这样的话,我将转义不安全的字符,使用词汇表来编码和解码用户给定的字符等。 但是,如果您有其他一些建议或经验,可以在没有准备好语句的情况下缓解 SQL 注入,我也会不胜感激!
谢谢!
答:
我会把我的发现作为答案发布,也许它可能对同一条船上的人有用:
由于缺乏任何其他想法,我走上了编码/解码的道路。
为此,最初的想法是使用自己的字典,但我认为十六进制编码应该足够了。
幸运的是,Dremio SQL 有一个函数,它可以为给定的十六进制字符串返回一个 BINARY 值。FROM_HEX
有了它,我可以(到目前为止)安全地构建动态查询,将任何类型的用户给定输入转换为十六进制字符串,然后在执行时转换回来,函数的行为有点像包装器。
尽管如此,这并不是一个完全平静的解决方案,但据我所知,目前没有更好的选择。我听说 Dremio 将实施准备好的声明(他们还没有这样做,这真是令人震惊),在那之前,让我们希望一切顺利!
评论
FROM_HEX