如果我们必须在 SQL Server 中动态使用数据库名称,如何修复 SQL 注入?

问题描述 投票:0回答:2

这是代码中的实现:模式名称来自配置文件,并且每个环境都不同。 Sonar 对此语句抛出 SQL 注入警报:

select * 
from dbName.dbo.stu_name;     <<dbname is the variable that comes from property file>>

我尝试了这些解决方案:

  1. 使用

    query.setParameter(?,dbname)
    。尝试动态传递数据库名称并修复了漏洞。调试时,查询抛出错误并且未执行。

  2. 已使用

    String.format(select * from \'%s\',tablename.replace("\'","\'\'"))
    - 漏洞已修复,但查询无法执行

我尝试了各种其他解决方案,但没有任何效果。

有人可以帮我吗?

sql-server security sql-injection
2个回答
0
投票

您可以做的“最佳”防御是使用动态 SQL。考虑到这是动态的数据库,并且基于先前的问题,我会建议这是从应用程序中发生的,因此这意味着您不需要需要由三部分组成的命名。相反,您可以在连接字符串中参数化数据库名称并使用两部分命名;不需要动态 SQL。

如果您必须使用动态 SQL,那么“最佳™️”防御方法是验证数据库名称,然后确保在将数据库名称注入动态语句时正确引用数据库名称。

在这里,我验证

sys.databases
中的数据库名称,然后使用
QUOTENAME
适当地引用该名称。如果数据库不存在,则不会运行查询(并且不会返回错误):

DECLARE @DatabaseName sysname = N'YourDatabaseName';

DECLARE @SQL nvarchar(MAX);
SELECT @SQL = N'SELECT * FROM ' + QUOTENAME(d.name) + N'.dbo.stu_name;'
FROM sys.databases d
WHERE d.name = @DatabaseName;

EXEC sys.sp_executesql @SQL;

0
投票

除了 Thom 关于验证数据库名称的建议之外,为了避免在查询中注入数据库名称,您可以在该查询的上下文中执行动态 SQL。如果不知何故

@DatabaseName
中有一些来自用户的垃圾,它就无法工作。

...
SET @sql = N'SELECT * FROM dbo.stu_name;';

DECLARE @db sysname, 
        @exec nvarchar(1024);

IF DB_ID(@DatabaseName) IS NOT NULL
BEGIN
  SET @db = QUOTENAME(DB_NAME(DB_ID(@DatabaseName)));
  SET @exec = @db + N'.sys.sp_executesql';

  EXEC @exec @sql;
END

我将其包裹在

DB_NAME(DB_ID(
中,以避免与 已经用 []
""
 引用
中传递的名称发生冲突。

这种方法的另一个好处是像

OBJECT_ID()
DB_NAME()
这样的函数可以工作,因为它们在该数据库的上下文中运行。

© www.soinside.com 2019 - 2024. All rights reserved.