diff --git a/.vs/SecureCore/v16/.suo b/.vs/SecureCore/v16/.suo index 4fe6fcb..70d44bb 100644 Binary files a/.vs/SecureCore/v16/.suo and b/.vs/SecureCore/v16/.suo differ diff --git a/SecureCore/Authentication/PasswordManager.cs b/SecureCore/Authentication/PasswordManager.cs index 9200720..7925ca4 100644 --- a/SecureCore/Authentication/PasswordManager.cs +++ b/SecureCore/Authentication/PasswordManager.cs @@ -6,6 +6,10 @@ namespace SecureCore.Authentication { public class PasswordManager { + //Add some pepper to the passwords for good measure: + //https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html + public static string Pepper { get; } = "rVk/OwQUw01qy76Q+5WimPk+NdqUMMghftMXyJzzckOj/+eFn056PDYzBD61E/ZNjRdgiMK6RhcHEcdfpJdbcw=="; + private static string ConnectionString = @"Server=DESKTOP-OEDDVKC\SQLEXPRESS;Database=main;Integrated Security=true;"; public PasswordManager() @@ -18,14 +22,14 @@ namespace SecureCore.Authentication ByteGenerator.GetRandomBytes(ref salt); - return (GetPasswordHash(password, salt), Convert.ToBase64String(salt)); + return (GetHash(password, salt), Convert.ToBase64String(salt)); } public static bool PasswordIsValid(string password, string salt, string passwordHash) { var saltBytes = Convert.FromBase64String(salt); - return passwordHash == GetPasswordHash(password, saltBytes); + return passwordHash == GetHash(password, saltBytes); } public static (string PasswordHash, string SaltHash) GetUserPasswordHash(int userId) @@ -49,9 +53,26 @@ namespace SecureCore.Authentication } } - private static string GetPasswordHash(string password, byte[] salt) + public static string HashStringData(string data, byte[] salt = null) { - return Convert.ToBase64String(KeyDerivation.Pbkdf2(password, salt, Settings.KeyType, Settings.Iterations, Settings.KeySize)); + if (salt == null) salt = new byte[0]; + + return GetHash(data, salt); + } + + public static string HashStringData(string data, string salt = "") + { + var saltBytes = new byte[0]; + + if(!string.IsNullOrEmpty(salt)) + saltBytes = Convert.FromBase64String(salt); + + return GetHash(data, saltBytes); + } + + private static string GetHash(string password, byte[] salt) + { + return Convert.ToBase64String(KeyDerivation.Pbkdf2($"{password}{Pepper}", salt, Settings.KeyType, Settings.Iterations, Settings.KeySize)); } } } diff --git a/SecureCore/Controllers/AuthController.cs b/SecureCore/Controllers/AuthController.cs index b1b4bda..dfaf438 100644 --- a/SecureCore/Controllers/AuthController.cs +++ b/SecureCore/Controllers/AuthController.cs @@ -21,9 +21,11 @@ namespace SecureCore.Controllers //Very the user has login data. if (!UserDataService.UserHasLoginData(info.UserName)) return Unauthorized("User doesn't have login creds"); - var (password, saltHash) = UserDataService.GetUserPasswordHash(info.UserName); + var (password, salt) = UserDataService.GetUserPasswordHash(info.UserName); + var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent]; + var ip = PasswordManager.HashStringData(HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(), salt); - if (PasswordManager.PasswordIsValid(info.Password, saltHash, password)) + if (PasswordManager.PasswordIsValid(info.Password, salt, password)) { if (HttpContext.Request.Cookies.ContainsKey("Session")) { @@ -33,7 +35,7 @@ namespace SecureCore.Controllers var sessionToken = SessionManager.CreateSessionToken(); - UserDataService.SetUserSessionToken(UserDataService.GetUserId(info.UserName), sessionToken, DateTime.Now.AddDays(7)); + UserDataService.SetUserSessionToken(UserDataService.GetUserId(info.UserName), sessionToken, DateTime.Now.AddDays(7), agent, ip); HttpContext.Response.Cookies.Append("Session", sessionToken, GetCookieOptions()); @@ -51,10 +53,12 @@ namespace SecureCore.Controllers { var (hash, salt) = PasswordManager.HashPassword(info.Password); var sessionToken = SessionManager.CreateSessionToken(); + var agent = HttpContext.Request.Headers[Microsoft.Net.Http.Headers.HeaderNames.UserAgent]; + var ip = PasswordManager.HashStringData(HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(), salt); try { - var i = UserDataService.RegisterNewUser(info.UserName, info.Email, hash, salt, sessionToken, DateTime.Now.AddDays(7)); + var i = UserDataService.RegisterNewUser(info.UserName, info.Email, hash, salt, sessionToken, DateTime.Now.AddDays(7),agent, ip); HttpContext.Response.Cookies.Append("Session", sessionToken, GetCookieOptions()); diff --git a/SecureCore/Services/UserDataService.cs b/SecureCore/Services/UserDataService.cs index 0db4dcf..eeedaa2 100644 --- a/SecureCore/Services/UserDataService.cs +++ b/SecureCore/Services/UserDataService.cs @@ -84,15 +84,17 @@ namespace SecureCore.Services } } - public static void SetUserSessionToken(int userId, string sessionToken, DateTime expirationDate) + public static void SetUserSessionToken(int userId, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress) { using (var connection = new SqlConnection(ConnectionString)) { - using (var command = new SqlCommand("INSERT INTO [Session]([Session Token], [Expiration Date], [User ID]) VALUES (@SessionToken, @ExpirationDate, @UserKey)", connection)) + using (var command = new SqlCommand("INSERT INTO [Session]([Session Token], [Expiration Date], [User ID], [User Agent], [IP Address]) VALUES (@SessionToken, @ExpirationDate, @UserKey, @UserAgent, @IpAddress)", connection)) { command.Parameters.AddWithValue("SessionToken", sessionToken); command.Parameters.AddWithValue("ExpirationDate", expirationDate); command.Parameters.AddWithValue("UserKey", userId); + command.Parameters.AddWithValue("UserAgent", userAgent); + command.Parameters.AddWithValue("IpAddress", ipAddress); connection.Open(); @@ -101,7 +103,7 @@ namespace SecureCore.Services } } - public static int RegisterNewUser(string userName, string email, string passwordHash, string saltHash, string sessionToken, DateTime expirationDate) + public static int RegisterNewUser(string userName, string email, string passwordHash, string saltHash, string sessionToken, DateTime expirationDate, string userAgent, string ipAddress) { using (var connection = new SqlConnection(ConnectionString)) { @@ -113,6 +115,8 @@ namespace SecureCore.Services command.Parameters.AddWithValue("Salt", saltHash); command.Parameters.AddWithValue("SessionToken", sessionToken); command.Parameters.AddWithValue("ExpirationDate", expirationDate); + command.Parameters.AddWithValue("UserAgent", userAgent); + command.Parameters.AddWithValue("IpAddress", ipAddress); connection.Open(); diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache index c26662d..387fd51 100644 Binary files a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache and b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.csprojAssemblyReference.cache differ diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll index 97e1b27..6464bac 100644 Binary files a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll and b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.dll differ diff --git a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.pdb b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.pdb index 39177d0..70585a7 100644 Binary files a/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.pdb and b/SecureCore/obj/Debug/netcoreapp3.1/SecureCore.pdb differ