这是代码中的实现:模式名称来自配置文件,并且每个环境都不同。 Sonar 对此语句抛出 SQL 注入警报:
select *
from dbName.dbo.stu_name; <<dbname is the variable that comes from property file>>
我尝试了这些解决方案:
使用
query.setParameter(?,dbname)
。尝试动态传递数据库名称并修复了漏洞。调试时,查询抛出错误并且未执行。
已使用
String.format(select * from \'%s\',tablename.replace("\'","\'\'"))
- 漏洞已修复,但查询无法执行
我尝试了各种其他解决方案,但没有任何效果。
有人可以帮我吗?
您可以做的“最佳”防御是不使用动态 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;
除了 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()
这样的函数可以工作,因为它们在该数据库的上下文中运行。