如何使用变量更改sql登录密码

问题描述 投票:4回答:3

我正在尝试使用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#app中的代码

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错误的语法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语法错误。

UPDATE2

使用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注入的可能性,但这不是最理想的方法。

-谢谢

c# sql-server
3个回答
6
投票

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

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

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

UPDATE

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是不够的。


0
投票

我在Azure SQL中使用上面的答案,我得到了“非有效标识符”错误,直到我用“EXEC(@sql)”代替“EXEC @sql”。见Msg 203, Level 16, State 2, is not a valid identifier

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


0
投票

在准备SQL查询字符串并使用c#SQL命令执行后,我总是收到无效标识符错误。这是因为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();
© www.soinside.com 2019 - 2024. All rights reserved.