我有一个系统,它接受随机SQL语句并返回执行结果。我想限制系统执行只读语句并拒绝任何更新/插入/删除等任何记录的语句。
有没有办法向数据库询问语句是否为只读语句而没有实际执行它?
注意:
正则表达式验证可能过于复杂,因为"禁止的单词"如果它们在评论或列名中,则可以。例如 这应该是一个有效的输入:
SELECT
a AS update_value,
'INSERT FOR FUN' AS q
FROM t --comment: should we delete stuff?
/*why not as long as you don't drop database*/
但这应该被拒绝:
UPDATE t SET a = 1
答案 0 :(得分:2)
我相信有两种解决方案:
您可以使用解析器sqlparser或ANTLR4来解析输入。然后很容易决定你有什么样的命令。 SQLParser在示例中有示例,说明如何对SQL命令进行分类。如果使用ANTLR4,则在使用gramar成功解析后获得解析树。如果你有一个SELECT语句,那么你必须在解析树中有select_statement
gramar规则。
您可以使用SET SHOWPLAN_XML ON以XML格式获取估算的计划。在SQL Server返回的XML中,您具有StatementType
属性,并且在您的情况下应该具有SELECT
值。
答案 1 :(得分:1)
不是很优雅,当然也不是防弹 - 但我们实施过的是围绕可疑SQL语句的SELECT
包装。
因此,如果您的用户输入
UPDATE t SET a = 1
然后我们将其包装成:
SELECT TOP 1 * FROM
(
UPDATE t SET a = 1
)
如果SELECT包装器内的任何内容是update
,delete
或insert
(更重要的是DROP TABLE
,TRUNCATE
,通常会产生错误等)。然后,您可以避免实际执行任何在很大程度上修改表的SQL语句。但是如果SQL语句是真正的SELECT语句,则没有错误,并返回1行。 (显然你可以修改或删除TOP 1
以适应)
虽然对存储过程(等)不是很有用,并且有很多限制,但在我们的上下文中它是完美的解决方案。 (我们已经让用户能够在我们的应用程序中自由键入SQL)
答案 2 :(得分:1)
旧线程,但是有一个更好的解决方案,它看起来如此优雅,我还是想添加它:与其将SQL语句包装在select()中,而不是将其包装在“ begin transaction”和“ rollback”中。您仍然可以从查询中获得所有结果,但是无论发生什么(可能是邪恶的事情),它们都不会持久