[英]How to authenticate user against salted and hashed password and username?
[英]How to authenticate user with hashed password?
我正在尝试使用libsodium实现安全密码存储,但docsTestWorks
、 hashesDontMatch
和wrongPassword
似乎总是正确的。 我不认为他们应该是。 我做错了什么(或很多事情)吗?
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);
}
我觉得这过于简单化了,我可能会遗漏很多东西......
我正在使用的 package:
dotnet add package Sodium.Core
我编写了一些使用System.Security.Cryptography
命名空间的扩展来简化这种工作。
添加到您的项目后, using System.Security.Cryptography
引用命名空间,然后您可以 hash 并比较任何字符串中的 hash。
例如:
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.");
我最终得到以下结果:
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
重载生成随机盐。
然后我最终添加了一个助手 class:
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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.