如果使用EXEC @Var
(不带括号 - 即不EXEC (@Var)
)SQL Server将查找匹配@Var
通过了名的存储过程。你可以使用三部分命名。
如果使用三部分名称调用sys.sp_executesql
,则将上下文设置为调用它的数据库。
所以你可以这样做零 SQL注入风险如下。
CREATE PROCEDURE dbo.test @dbname SYSNAME,
@col SYSNAME
AS
SET NOCOUNT, XACT_ABORT ON;
DECLARE @db_sp_executesql NVARCHAR(300) = QUOTENAME(@dbname) + '.sys.sp_executesql'
EXEC @db_sp_executesql N'
SELECT TOP 100 *
FROM sys.columns
WHERE name = @col',
N'@col sysname',
@col = @col
即使以上是不可能的我仍然认为,这是完全可以使用动态SQL在安全的方式在这里。
CREATE PROCEDURE dbo.test
@dbname SYSNAME, /*Use Correct Datatypes for identifiers*/
@col SYSNAME
AS
SET NOCOUNT ON
SET XACT_ABORT ON
IF DB_ID(@dbname) IS NULL /*Validate the database name exists*/
BEGIN
RAISERROR('Invalid Database Name passed',16,1)
RETURN
END
DECLARE @dynsql nvarchar(max)
/*Use QUOTENAME to correctly escape any special characters*/
SET @dynsql = N'USE '+ QUOTENAME(@dbname) + N'
SELECT TOP 100 *
FROM sys.tables
WHERE name = @col'
/*Use sp_executesql to leave the WHERE clause parameterised*/
EXEC sp_executesql @dynsql, N'@col sysname', @col = @col
除非在SQL Server明确禁止它的情况下,如何在存储过程中使用'USE'命令? –
JNK
2010-10-15 17:02:52
感谢您的信息! – jjoras 2010-10-15 17:27:22
Whoops - yep,SQL Server不允许在存储过程中使用。答案已更新。 – 2010-10-16 17:18:05