有没有办法动态编写脚本以在存储过程中向 Microsoft SQL Server 添加域 + 用户?

Is there a way for me to dynamically write a script to add a domain+user to Microsoft SQL server in a stored procedure?

提问人:Nick Weidemann 提问时间:8/2/2021 最后编辑:Thom ANick Weidemann 更新时间:8/2/2021 访问量:137

问:

我必须在下面使用这个确切的脚本:

ALTER PROCEDURE [dbo].[sp_CheckIfSQLLoginExistsAndCreateLogin] 
    @SearchDomain NVARCHAR(MAX),
    @SearchUsername NVARCHAR(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
    
    DECLARE @sql NVARCHAR(max);
    DECLARE @params NVARCHAR(MAX);

    IF @SearchUsername != ''
    BEGIN
        SET @sql = N'IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE [name] =  @Domain\@Username) CREATE LOGIN [@Domain\@Username] FROM WINDOWS';
        SET @params = N'@Username NVARCHAR(MAX), @Domain NVARCHAR(MAX)';
    END
            
    exec sp_executesql @sql, @params, @Username=@SearchUsername, @Domain=@SearchDomain      
END

我遇到的问题是,每次调用此SP时,我都会收到以下错误:

Error Description

使用此数据:@SearchDomain = OFFICE,@SearchUsername = BJackson

sql-server 存储过程 sql 注入

评论

2赞 Squirrel 8/2/2021
请使用格式化文本而不是图像
3赞 Nick.Mc 8/2/2021
每当动态 SQL 出现问题时,首先要做的就是添加、检查并运行输出print @sql
2赞 Thom A 8/2/2021
SQL 不是一种脚本语言,变量名称不会由字符串中的值转义。To 对象名称将被视为文本名称,而不是存储在名为 的变量中的名称。[@Domain][@Domain]@Domain
1赞 Thom A 8/2/2021
@NickWeidemann我怀疑......你没有.WHERE [name] = @Domain\@UsernameWHERE [name] = '@Domain\@Username'
1赞 Thom A 8/2/2021
你的意思是对你没有帮助......如果你的语句和你得到的语句不是你所期望的,那是因为你的SQL错了......PRINT

答:

2赞 Thom A 8/2/2021 #1

这里的问题是你认为SQL是一种脚本语言;事实并非如此。例如,表示文字字符串,而不是文字字符串替换为变量中的值。'@Domain''@Domain''@Domain'@Domain

如果你有,你没有得到价值,你得到价值,为什么?因为它们是字面意思EXEC sys.sp_executesql N'SELECT '@V1 + @V2';', N'@V1 varchar(30), @V2 varchar(30)','This', 'works';'Thisworks''@V1 + @V2'

您需要做的是安全地注入对象名称的参数,并正确参数化:WHERE

ALTER PROCEDURE [dbo].[CheckIfSQLLoginExistsAndCreateLogin] --removed prefix
    @SearchDomain sysname, --Corrected datatype
    @SearchUsername sysname  --Corrected datatype
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    
    DECLARE @sql NVARCHAR(max);
    DECLARE @Login sysname = CONCAT(@SearchDomain,'\',@SearchUsername);

    IF @Login != ''
    BEGIN
        SET @sql = N'IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE [name] = @Login) CREATE LOGIN ' + QUOTENAME(Login) + N' FROM WINDOWS';
    END
            
    EXEC sys.sp_executesql @sql, N'@Login sysname', @Login;
END;

评论

1赞 Nick Weidemann 8/2/2021
我完全明白你现在上面的例子的意思!CONCAT函数肯定也有助于堆。我认为我如此困惑的原因是以前的开发人员在代码库中写得非常糟糕,所以当我尝试为它创建一个 SP 时 - 我只是按原样复制它并试图将其全部参数化。谢谢你帮助我学到@Larnu的东西。
-1赞 MohammadAmin Moazami 8/2/2021 #2

下面是一个简单的示例:

CREATE OR ALTER PROCEDURE [dbo].[sp_CheckIfSQLLoginExistsAndCreateLogin] 
    @SearchDomain NVARCHAR(MAX),
    @SearchUsername NVARCHAR(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
    
    DECLARE @sql NVARCHAR(max);
    DECLARE @params NVARCHAR(MAX);

  IF @SearchUsername != ''
    BEGIN
        SET @sql = N'IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE [name] = '''+ @SearchDomain +'\'+ @SearchUsername +''') CREATE LOGIN [@Domain\@Username] FROM WINDOWS';
        SET @params = N'@Username NVARCHAR(MAX), @Domain NVARCHAR(MAX)';
    END
            
    exec sp_executesql @sql, @params, @Username=@SearchUsername, @Domain=@SearchDomain      
END