我正在尝试使用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注入的可能性,但这不是最理想的方法。
-谢谢
您需要在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
是不够的。
我在Azure SQL中使用上面的答案,我得到了“非有效标识符”错误,直到我用“EXEC(@sql)”代替“EXEC @sql”。见Msg 203, Level 16, State 2, is not a valid identifier
另外,我不得不使用“ALTER USER”而不是“ALTER LOGIN”
在准备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();