我有一个登录窗口,可以从用户那里获取用户名和密码,我想知道处理密码的最佳方法。用户名只是常规文本框,但密码是PasswordBox。我将用户名直接传递给ViewModel,但只有在使用Code-Behind单击Login按钮后才在ViewModel上设置SecureString属性。设置密码安全串后,我想验证。
我现在正在编写LoginBox,但我还没有完全解决该模型。我该如何在SQL Server中存储密码?我只是将SecureString的内容写入SQL,然后在用户尝试登录时尝试比较它吗?
答案 0 :(得分:4)
你永远不应该存储密码 - 甚至不加密......
只需存储密码的哈希值(只要哈希以安全的方式实现,就可以阻止密码被检索),并且对于验证,您可以用相同的方式对用户提供的密码进行哈希处理并比较结果...
有标准可以这样做:
上述标准使得很难使用彩虹表等,因为它使得计算非常昂贵,因为除了盐之外它还使用了几轮...因此散列例如慢1000倍(1000轮)但是这样正是你想要的 - 攻击者需要做同样的计算,因此需要1000倍的进动力或时间才能通过蛮力实现目标...
您可以将结果直接存储为VARBINARY,也可以在Base64-或HEX编码字节后将其存储为VARCHAR ...您需要将盐与其一起存储(只要每个密码都获得它,就没有安全风险)拥有独特的加密安全生成的随机盐)。
答案 1 :(得分:0)
在我之前的演出中,我们将密码存储为散列/加密/加盐值(当时使用MD5)作为VARBINARY(32)
。为了稍后比较密码,我们将比较我们存储的加密+盐渍值与尝试密码的加密+盐渍值,而不是尝试解密密码。如果他们匹配,他们进来,如果他们不匹配,他们没有进入。
哈希工作是在中间层完成的(两者都是为了最初保存密码和以后进行比较),但是基于SQL Server的例子(停止@Yahia的抱怨,这并不是要告诉你最安全的方式,我只是用一个非常轻量级的例子来说明方法.MD5对你来说还不够强大?你可以使用不同的,更复杂的算法以及更高级的salting技术,特别是如果你在应用程序层中执行散列强>):
CREATE TABLE dbo.Users
(
UserID INT IDENTITY(1,1) PRIMARY KEY,
Username NVARCHAR(255) NOT NULL UNIQUE,
PasswordHash VARBINARY(32) NOT NULL
);
创建用户的过程(无错误处理或欺骗预防,只是伪)。
CREATE PROCEDURE dbo.User_Create
@Username NVARCHAR(255),
@Password NVARCHAR(16)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @salt NVARCHAR(16) = '$w0rdf1$h';
INSERT dbo.Users(Username, Password)
SELECT @Username,
CONVERT(VARBINARY(32), HASHBYTES('MD5', @Password + @Salt));
END
GO
现在是验证用户身份的过程。
CREATE PROCEDURE dbo.User_Authenticate
@Username NVARCHAR(255),
@Password NVARCHAR(16)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @salt NVARCHAR(16) = '$w0rdf1$h';
IF EXISTS
(
SELECT 1 FROM dbo.Users
WHERE Username = @Username AND
PasswordHash = CONVERT(VARBINARY(32), HASHBYTES('MD5', @Password + @salt))
)
BEGIN
PRINT 'Please, come on in!';
END
ELSE
BEGIN
PRINT 'You can keep knocking but you cannot come in.';
END
END
GO
实际上,您可能会在应用程序中执行散列,并将散列值作为VARBINARY(32)传递 - 这使得从任何地方“嗅探”实际的明文密码变得更加困难。并且您可能不会使用代码以纯文本形式存储salt,而是从其他地方检索它。
这肯定比存储未加密的密码更安全,但它删除了检索密码的能力。在我看来是双赢的。