如何用哈希密码验证用户?

问题描述 投票:0回答:1

我正试图使用以下方法来实现安全密码存储 docsTestWorks, hashesDontMatchwrongPassword 似是 始终 是的 我觉得不应该是这样的。我是不是做错了什么(或者说很多事情)?

public async Task<IUser> Authenticate(ICredentials credentials)
{
    using var connection = _databaseGateway.Connection;
    connection.Open();

    const string PASSWORD = "Correct Horse Battery Staple";
    var hash = PasswordHash
        .ScryptHashString(PASSWORD);
    var docsTestWorks = PasswordHash.ScryptHashStringVerify(hash, PASSWORD);

    var incomingHash = PasswordHash
        .ScryptHashString(credentials.Password);
    var test1 = PasswordHash
        .ScryptHashString("myPassword");
    var test2 = PasswordHash
        .ScryptHashString("myPassword");
    var hashesDontMatch = test1 != test2;
    var users = await connection.GetAllAsync<User>();
    var existingUser = users
        .Single(u => u.Username == credentials.Username);
    var wrongPassword = !PasswordHash
        .ScryptHashStringVerify(existingUser.PasswordHash, credentials.Password);

    if (wrongPassword)
        throw new AuthenticationException(Error.WrongPassword,
            "Error: Incorrect Password.");

    return AddToken(existingUser);
}

我觉得这太简单了,我可能漏掉了很多东西......

我正在使用的软件包。

dotnet add package Sodium.Core
c# asp.net-core passwords password-hash libsodium
1个回答
0
投票

我写了一些使用 System.Security.Cryptography 命名空间来简化这种工作。

https:/github.comjscarleCrypto.NETblobmasterCrypto.NETSystem.Security.Cryptography.Extensions.cs。

一旦添加到您的项目中,请用以下方式引用命名空间 using System.Security.Cryptography然后你可以从任何字符串中哈希和比较哈希值。

比如说

string password1 = "some password";
string hash1 = password1.Hash();

string password2 = "some other password";
string hash2 = password2.Hash();

string password3 = "some password";
string hash3 = password3.Hash();

Console.WriteLine($"{password1} = {hash1}");
Console.WriteLine($"{password2} = {hash2}");
Console.WriteLine($"{password3} = {hash3}");

if (password1.CompareToHash(hash2))
    Console.WriteLine("hash1 and hash2 match.");
else
    Console.WriteLine("hash1 and hash2 do not match.");

if (password1.CompareToHash(hash3))
    Console.WriteLine("hash1 and hash3 match.");
else
    Console.WriteLine("hash1 and hash3 do not match.");

0
投票

我的结果是:

public async Task<IUser> Authenticate(ICredentials credentials)
{
    using var connection = _databaseGateway.Connection;
    connection.Open();
    var users = await connection.GetAllAsync<User>();
    const int expectedUserCount = 1;
    var existingUsers = users
        .Where(u => u.Username == credentials.Username);

    if (existingUsers.Count() != expectedUserCount)
        throw new AuthenticationException(Error.UserDoesNotExist,
            "Error: There is no single user exists with the username given.");
    var existingUser = existingUsers.Single();

    var salt = existingUser.PasswordSalt;
    // TURN ON FOR REGISTERING USER PW
    // salt = PasswordHash.ScryptGenerateSalt();
    var password = Encoding.UTF8.GetBytes(credentials.Password);
    var hash = PasswordHash.ScryptHashBinary(password, salt);
    // TURN ON FOR REGISTERING USER PW
    // await connection.ExecuteAsync(
    //    "UPDATE user SET PasswordHash=@hash, PasswordSalt=@salt WHERE UserName=@username;",
    //    new {hash, salt, username = credentials.Username});

    var wrongPassword = !hash.SequenceEqual(existingUser.PasswordHash);

    if (wrongPassword)
        throw new AuthenticationException(Error.WrongPassword,
            "Error: Incorrect Password.");

    return AddToken(existingUser);
}

怀疑 此处 是正确的,我想。它似乎每次都会随机生成盐与 string 方法的重载。


然后我最后添加了一个辅助类。

using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sodium;

namespace Services
{
    public static class HashingService
    {
        public static bool IsGeneratedBy(
            this IEnumerable<byte> existingHash,
            string plaintextPassword,
            byte[] salt
        )
        {
            var password = Encoding.UTF8.GetBytes(plaintextPassword);
            var generatedHash = PasswordHash.ScryptHashBinary(password, salt);
            var passwordIsCorrect = generatedHash.SequenceEqual(existingHash);
            return passwordIsCorrect;
        }
    }
}

并像这样使用:

public async Task<IUser> Authenticate(ICredentials credentials)
{
    using var connection = _databaseGateway.Connection;
    connection.Open();
    var users = await connection.GetAllAsync<User>();
    const int expectedUserCount = 1;
    var existingUser = users
        .Single(u => u.Username == credentials.Username);

    var wrongPassword = !existingUser.PasswordHash.IsGeneratedBy(
        credentials.Password, existingUser.PasswordSalt);

    if (wrongPassword)
        throw new AuthenticationException(Error.WrongPassword,
            "Error: Incorrect Password.");

    return AddToken(existingUser);
}
© www.soinside.com 2019 - 2024. All rights reserved.