调试在SQL端无法散列

时间:2016-08-20 09:06:03

标签: c# asp.net sql-server

我试图让哈希为密码工作。他们目前没有进行调试,无法进行调试。

目前我使用的哈希算法是SHA1

我的表格(称为Users)包括:

  • [phone] varchar(32)
  • [password] binary(20)

要填充我的数据库,我使用此查询:

DELETE FROM Users

INSERT INTO Users (phone, password)
VALUES ('0526487612', HASHBYTES(SHA1, 'admin123'))

当我登录时,我这样做:

command = connection.CreateCommand();
command.CommandText = "SELECT * FROM Users WHERE phone=@UName AND password=HASHBYTES('SHA1', @PWord)";

command.Parameters.AddWithValue("@UName", username);
command.Parameters.AddWithValue("@PWord", password);

reader = command.ExecuteReader();

if (reader.HasRows)
{
    // ...
}

当我尝试登录时(使用用户名0526487612和密码admin123),它永远不会进入if(...)(意味着读者找不到任何匹配的行)查询)。

如果我不填写密码,一切都有效 - 这意味着问题不在其他地方。

我尝试使用不同的哈希算法(SHA2_256)并相应地更改SQL Server数据类型(binary(32)),但结果是一样的。

我正在使用Microsoft SQL Server 2014;我不知道如何进一步调试。

1 个答案:

答案 0 :(得分:3)

我个人认为,当您直接从SQL Server Management Studio运行查询并运行以下语句时:

DELETE FROM Users;
INSERT INTO Users (phone, password)
VALUES ('0526487612', HASHBYTES('SHA1', 'admin123'));

您的密码(admin123)是VARCHAR。现在,当您执行代码时,它不会像那样执行:

SELECT * FROM Users WHERE phone=@UName AND password=HASHBYTES('SHA1', @PWord);

相反,它执行此语句(您的参数以NVARCHAR发送):

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', @p1)'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';

@p1(您的密码)转换为VARCHAR可以解决问题。

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', CAST(@p1 AS VARCHAR(30)))'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';

运行此证明NVARCHAR输出不同的二进制文件:

SELECT HASHBYTES('SHA1', 'admin123') AS VarcharSHA1
    , HASHBYTES('SHA1', N'admin123') AS nVarcharSHA1;

结果:

VarcharSHA1                                 nVarcharSHA1
--------------------------------------------------------------------------------------
0xF865B53623B121FD34EE5426C792E5C33AF8C227  0xB7BC3A1B04D9E165C6762B0A1CDE5226DF5B6A6A

完整示例:

IF OBJECT_ID('Users', 'U') IS NOT NULL
    DROP TABLE Users;

CREATE TABLE Users
(
    [phone] VARCHAR(30)
    , [password] BINARY(20)
);

INSERT INTO Users ([phone], [password])
VALUES ('0526487612', HASHBYTES('SHA1', 'admin123'));

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', @p1)'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';
-- Doesn't bring result back

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', CAST(@p1 AS VARCHAR(30)))'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';
-- Brings results back

TRUNCATE TABLE Users;
INSERT INTO Users ([phone], [password])
VALUES ('0526487612', HASHBYTES('SHA1', N'admin123'));
                                  --    ^
                                  --    |
                                  -- Notice this

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', @p1)'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';
-- Brings results back

EXEC sp_executesql N'SELECT * FROM Users WHERE phone=@p0 AND password=HASHBYTES(''SHA1'', CAST(@p1 AS VARCHAR(30)))'
    , N'@p0 NVARCHAR(100), @p1 NVARCHAR(100)'
    , @p0 = N'0526487612'
    , @p1 = N'admin123';
-- Doesn't bring result back

所以我已经指出了问题,现在由你决定如何修复它。要么总是将密码转换为VARCHAR,要么在对其进行散列时使用等效的unicode。

更新

显然你没有插入密码并将其哈希为NVARCHAR,但是你必须稍微修改你的c#代码以传递你想要的值数据类型,而不是数据类型ADO.NET自己选择。请阅读这篇文章:Can we stop using AddWithValue() already?了解更多信息。

基于此,您可以像这样更新代码,它应该可以正常工作:

command = connection.CreateCommand();
command.CommandText = @"
  SELECT *
  FROM Users
  WHERE phone = @UName
    AND password = HASHBYTES('SHA1', @PWord)";

//Add parameters like that and it will pass in correct data type
command.Parameters.Add("@UName", SqlDbType.VarChar, 50).Value = username;
command.Parameters.Add("@PWord", SqlDbType.VarChar, 50).Value = password;

//command.Parameters.AddWithValue("@UName", username);
//command.Parameters.AddWithValue("@PWord", password);

reader = command.ExecuteReader();

if (reader.HasRows)
{
    // ...
}