6

我正在尝试使用 Alter LOGIN 更新现有 SQL 登录的密码

我知道以下作品

ALTER LOGIN [username1] WITH PASSWORD = 'somenewpassword123';

但是,当我尝试使用局部变量时

DECLARE @newpass nvarchar(max);
SET @newpass = 'P@ssw0rd12345';
ALTER LOGIN [username1] WITH PASSWORD = @newpass;

这失败了。在变量中添加 [] 大括号似乎可以在 SSMS 查询编辑器中解决这个问题,但是通过在 C# 中写出查询以编程方式使用它会失败,因为上述语句具有相同的错误(PASSWORD 处的语法错误)

c# 应用程序中的代码

public static int UpdateSqlLoginPassword(DbContext context, string loginName, string password)
{
 try
 {
  string updatePassword =
         @"  SET NOCOUNT ON
          DECLARE @loginName AS nvarchar(max) = {0}
          DECLARE @password AS nvarchar(max) = {1}
          EXEC('
          USE master
          ALTER LOGIN ['+ @loginName + '] WITH PASSWORD = ['+ @password + ']
          ')";
  return context.Database.ExecuteSqlCommand(updatePassword, loginName, password);
 }
 catch (Exception)
 {  
  return -2;
 }
}

我也尝试过对密码进行哈希处理(认为这是变量的问题),但这里的语法不被接受

DECLARE @newpass nvarchar(max);
SET @newpass = 'P@ssw0rd12345';
DECLARE @hashedpass varbinary(max);
SET @hashedpass = HASHBYTES('SHA1', CONVERT(nvarchar(max),@newpass));

ALTER LOGIN [newuser10] WITH PASSWORD = @hashedpass HASHED;
SELECT @hashedpass;

谁能帮助我了解如何使用变量而不是固定值在 sql 中更新登录密码?

提前致谢

更新

根据查理的建议,我还尝试了以下方法

public static int UpdateSqlLoginPassword(DbContext context, string loginName, string password)
        {
            try
            {
                string updatePassword =
                    @"ALTER LOGIN [' + @loginName +'] WITH PASSWORD =  @password ";
                return context.Database.ExecuteSqlCommand(updatePassword, new SqlParameter("loginName", loginName), new SqlParameter("password", password));
            }
            catch (Exception)
            {  
               return -2;
            }
        }

这仍然会生成 sqlException Incorrect Syntax new '@password'。如果我支撑参数

public static int UpdateSqlLoginPassword(DbContext context, string loginName, string password)
        {
            try
            {
                string updatePassword =
                    @"ALTER LOGIN [' + @loginName +'] WITH PASSWORD =  [' + @password +']";
                return context.Database.ExecuteSqlCommand(updatePassword, new SqlParameter("loginName", loginName), new SqlParameter("password", password));
            }
            catch (Exception)
            {  
               return -2;
            }
        }

然后我在 PASSWORD 附近生成一个 sqlException Incorrect syntax。

更新2

使用 Charlie 的更新建议,我尝试使用 QuoteName 函数

        string sql = @"DECLARE @sql NVARCHAR(500)
              SET @sql = 'ALTER LOGIN ' + QuoteName(@loginName) +
                ' WITH PASSWORD = ' + QuoteName(@password, '''') 
                EXEC @sql";
        return context.Database.ExecuteSqlCommand(sql, new SqlParameter("loginName", loginName), new SqlParameter("password", password));

虽然查询字符串的格式似乎正确,但会引发以下 SQLException *名称 'ALTER LOGIN [newuser10] WITH PASSWORD = 't#P@ssw0rd'' 不是有效标识符。

编辑

经过更多阅读后,错误是由包装@sql的语法错误生成的,允许查询无错误地执行

 string sql = @"DECLARE @sql NVARCHAR(500)
                  SET @sql = 'ALTER LOGIN ' + QuoteName(@loginName) +
                    ' WITH PASSWORD = ' + QuoteName(@password, '''') 
                    EXEC(@sql)";

附带说明:只需构建字符串并将其运行为

string updatePassword = "USE MASTER ALTER LOGIN [" + loginName + "] WITH PASSWORD =  '" + password + "'";
return context.Database.ExecuteSqlCommand(updatePassword);

以上也是一种变通方法,更新sql登录。虽然此代码的实现最大限度地减少了 sql 注入的可能性,但这并不是最理想的方法。

-谢谢

4

3 回答 3

8

您需要在DbContext级别使用参数。有关更多详细信息,请参阅此答案,但是,这是一个代码示例(改编自同一页面):

string sql = "ALTER LOGIN @loginName WITH PASSWORD = @password";
ctx.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("loginName", loginName),
    new SqlParameter("password", password));

在此处(以及在任何地方)使用参数的目的是防止 SQL 注入攻击。鉴于您正在编写更改密码的代码,这一点尤其重要。

更新

ALTER LOGIN 语句不适用于变量;它必须通过动态 SQL 来完成。以下是更新代码的示例:

string sql = @"DECLARE @sql NVARCHAR(500)
               SET @sql = 'ALTER LOGIN ' + QuoteName(@loginName) + 
                    ' WITH PASSWORD= ' + QuoteName(@password, '''') 
               EXEC @sql ";
ctx.Database.ExecuteSqlCommand(
    sql,
    new SqlParameter("loginName", loginName),
    new SqlParameter("password", password));

请注意,我们仍然使用 SqlParameters 来防止 SQL 注入攻击。我们还使用 T-SQL 方法QuoteName在我们生成的 SQL 中进行适当的引用;但是这种方法只是将任何[字符(在第一次调用中)或'字符(在第二次调用中)加倍。SQL注入攻击还有很多其他的载体,所以仅仅依靠QuoteName是不够的。

于 2013-02-13T16:27:53.420 回答
0

我将上述答案与 Azure SQL 一起使用,并且在将“EXEC @sql”替换为“EXEC (@sql)”之前,我收到了“不是有效标识符”错误。请参阅消息 203,级别 16,状态 2,不是有效标识符

此外,我不得不使用“ALTER USER”而不是“ALTER LOGIN”

于 2016-08-02T15:54:32.107 回答
0

在准备 SQL 查询字符串并使用 c# SQL 命令执行后,我总是收到 Invalid Identifier 错误。这是因为QuoteName应该在执行更改密码 sql 语句之前执行。所以我使用上述解决方案创建了存储过程,然后从 c# 调用过程,它对我有用。

Create procedure usp_updateSqlUsers(@loginName nVarchar(100), @pwd nvarchar(100))
as
 begin
DECLARE @sql NVARCHAR(500) 
set @sql='Alter LOGIN  '+QUOTENAME(@loginName)+' WITH 
  password=N'+ QUOTENAME(@pwd,'''')
  exec sp_sqlexec @sql

 end

然后从 C# 执行

SqlCommand cmd = new SqlCommand("usp_updateSqlUsers", con) {CommandType = 
 CommandType.StoredProcedure};
 var passwordParam = new SqlParameter("@pwd", password);
 var sqlLoginParameter = new SqlParameter("@loginName", "SqlLoginName");
 cmd.Parameters.Add(passwordParam);
 cmd.Parameters.Add(sqlLoginParameter);
 cmd.ExecuteNonQuery();
于 2018-12-04T07:06:56.690 回答