【问题标题】:Encrypted Password corruption - some saved as encrypted, some not encrypted, some not saved加密密码损坏 - 一些保存为加密,一些未加密,一些未保存
【发布时间】:2015-03-28 21:16:53
【问题描述】:

我正在编写一个使用 2008 SQL Server 数据库的旧式 ColdFusion 应用程序。我对如何设置 SQL Server 数据库知之甚少,但我希望如果我分享一些症状,有人可能会对检查内容提出一些建议。

数据库使用对称密钥来保护用户密码。我有一个用户表,其中包含用户名、密码等作为字段。密码已加密。

数据库中的大多数旧用户都可以正常工作。用户可以毫无问题地使用网站登录、更改密码等。对于用于测试的记录,我在 SQL Server 中使用 SQL 更改了密码,而不是通过网站:“update users set password = "fluffy" where userID in (6543, 7654, 8765)”等。

当我这样做时,会发生一些事情:

  • 我第一次使用 USERID 6543 永远无法登录网站 和密码“蓬松”——但它总是在第二次工作。

  • 当我运行存储过程exec get_user_unencrypt_by_id 6543时,
    结果返回“NULL”作为密码。

  • 当我运行查询 select * from Users 时,我看到了预期的
    大多数密码字段中的符号/乱码,但对于用户
    6543、7654、8765,我看“毛茸茸”的。

  • 当我运行查询 select * from users where password is null 时,我得到 没有结果。

我为解决问题所做的工作:

我运行以下 SQL 来打开和重置主密钥:

OPEN MASTER KEY DECRYPTION BY PASSWORD = ''
ALTER MASTER KEY ADD ENCRYPTION BY SERVICE MASTER KEY
Close Master Key
GO

这似乎没有效果。

我尝试使用 SQL 更新损坏的密码

  update users set password = EncryptByKey(Key_GUID('PASS_Key_01'), 'fluffy') 
  where userID in (6543, 7654, 8765)"

当我尝试这样做时,这些用户在使用密码“fluffy”时被锁定了。

我已尝试通过网站重置密码。这似乎仅适用于密码未损坏的记录。如果我使用其中一个损坏的密码执行此操作,它似乎可以暂时工作,但稍后(第二天),密码再次损坏。

我的名为 get_user_unencrypt_by_id 的 SP 是这样的:

OPEN SYMMETRIC KEY PASS_Key_01
   DECRYPTION BY CERTIFICATE UserPasswords0324

SELECT       userid, username, CONVERT (nvarchar, 
DecryptByKey([password])) as 'password', [role], firstname, lastname, 
Add1, Add2, City, [State], Zip, Phone, Fax, 
FROM         users

我不确定还可以尝试什么,所以我很乐意为您提供任何建议或想法。谢谢。

已编辑以添加更多细节。在继续调查中,我了解到桌子上有一个触发器。这是触发器。

/****** Object:  Trigger [dbo].[encrypt_password_on_update]
Script Date: 4/1/2015 8:55:44 AM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[encrypt_password_on_update] 
   ON  [dbo].[USERS] 
      after update
AS 
BEGIN

    /***The purpose of this trigger is to encrypt a password that was 
update by the user.  When the update statement updates the password,  
this encrypts it before storing it in the db***/

DECLARE @updatecount int
DECLARE @userid  int
DECLARE @password nvarchar(50)
DECLARE @temp_encryt_password nvarchar(50)

select @updatecount = (select count(userid) from inserted)

if (@updatecount = '1')
BEGIN
SELECT @userid  = (SELECT userid FROM Inserted)

OPEN SYMMETRIC KEY PASS_Key_01
   DECRYPTION BY CERTIFICATE UserPasswords0324

if (@userid != '' and @userid is not null)
    BEGIN

        select @temp_encryt_password = (select   
EncryptByKey(Key_GUID('PASS_Key_01'), [password]) from users where  
userid = @userid)

    /***If the password is already encrypted (if the update was for   something else other than the password) we don't want to reencrypt***/
        if ( CONVERT (nvarchar, DecryptByKey(@temp_encryt_password))  is not null)
        BEGIN
            update USERS 
            set [password] = EncryptByKey(Key_GUID('PASS_Key_01'), [password])
            where userid = @userid
        END

    END
END
END

GO

【问题讨论】:

  • 您的示例中的密码永远不会为空,exec get_user_unencrypt_by_id 6543 在无法成功时只是简单地返回null,这就是select...where null 失败的原因。
  • 谢谢。我认为这是有道理的。不过,它存储的不是密码,我不知道它是什么。我还没有解决这个问题,所以我欢迎其他关于寻找什么的建议。
  • 但稍后(第二天),密码再次损坏发生这种情况时的确切事件链是什么以及“密码”列的值是什么每一步?跟踪这些可以帮助您弄清楚发生了什么,例如值是否被双重加密......请记住,您可以将值记录到另一个表inside触发器以进行调试。即步骤1)您重置密码2)用户通过应用程序登录3)用户通过应用程序更改密码4)用户使用新密码再次登录5)......?
  • 也就是说,为什么要加密密码? Typically hashing is preferred.
  • 我相信通过网站更新密码 - 分别通过业务逻辑/api创建密码的哈希值,然后将其存储在数据库中。这就是为什么当直接更新时,你会得到简单英语的 'fluffy' 字符串。在将其存储在数据库中之前,您必须使用对其进行哈希处理的函数。您可能需要检查是否存在更新用户密码的存储过程。 update_user_password_by_id 之类的东西

标签: sql-server encryption coldfusion


【解决方案1】:

我相信我已经解决了自己的问题。问题出现在我使用类似

的查询直接在数据库中重置的密码中
update users set password = "fluffy" where userID in (6543, 7654, 8765)

然后实际加密密码的触发器会查找单个记录:

select @updatecount = (select count(userid) from inserted)

if (@updatecount = '1')
BEGIN
...

所以密码被本地存储在数据库中,并且从未加密,因为我同时更新了多条记录。

然后,当用户尝试登录该站点时,身份验证将失败——返回解密密码的 SP 将返回 NULL。该失败将触发用户数据库的更新以增加失败的登录尝试次数。该查询将触发密码加密,并且用户第二次尝试登录时,身份验证将起作用。因此,出于测试目的,我需要的关键是使用以下一系列查询重置数据库中的密码:

update users set password = "fluffy" where userID = 6543
GO
update users set password = "fluffy" where userID = 7654
GO
update users set password = "fluffy" where userID = 8765
GO

【讨论】:

  • 啊,我想知道,但没有时间研究它.. 感谢发布决议。不过,这提出了一个很好的观点。由于triggers fire per action - not record 真正应该重写触发器以处理多条记录,以防止同样的事情再次发生,或者从应用程序端(如果它曾经修改过多条记录)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-19
  • 1970-01-01
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
相关资源
最近更新 更多