在我之前的演出中,我们将密码存储为哈希/加密/加盐值(当时使用 MD5)作为VARBINARY(32)
. 为了稍后比较密码,而不是尝试解密密码,我们会将我们存储的加密 + 加盐值与正在尝试的密码的加密 + 加盐值进行比较。如果他们匹配,他们进入,如果他们不匹配,他们没有进入。
散列工作是在中间层完成的(最初保存密码和稍后比较),但是一个基于 SQL Server 的示例(为了阻止@Yahia 的抱怨,这并不是要告诉你最安全的方法,我我只是用一个非常轻量级的例子来说明方法。MD5 对你来说不够强大吗?你可以使用不同的更复杂的算法以及更高级的加盐技术,特别是如果你在应用层执行散列):
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) 传递 - 这使得从任何地方“嗅探”实际的明文密码变得更加困难。而且您可能也不会将盐与代码一起以纯文本形式存储,而是从其他地方检索它。
这绝对比存储未加密的密码更安全,但它消除了检索密码的能力。在我看来是双赢的。