Hashing legacy salted passwords with ASP.NET Identity - asp.net

I have an existing membership database where passwords are a hash of both username and a unique id. As I understand, ASP.NET Identity will take care of salting passwords for you.
However, I need my old hashed passwords to work until they are updated (i.e. they need to work on the first login at which point I'll update it).
The IPasswordHasher has method: VerifyHashedPassword(string hashedPassword, string providedPassword). This method doesn't allow me to pass in any sort of salt. I realize I don't need to provide a value for any new hashed passwords, but for my existing ones I need to do a legacy check.
public class CoolGuyPasswordHasher : PasswordHasher {
public IdentityContext DbContext { get; set; }
// Custom hashing used before migrating to Identity
public static string GetSHA1Hash(string password, string guid) {
string passWithSalt = String.Concat(password, guid);
return FormsAuthentication.HashPasswordForStoringInConfigFile(passWithSalt, "SHA1");
}
// Verify if the password is hashed using SHA1. If yes, rehash using ASP.NET Identity Crypto which is more secure
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) {
//I can't pass in my salt!
if (String.Equals(hashedPassword, GetSHA1Hash(providedPassword, wheresTheSalt), StringComparison.InvariantCultureIgnoreCase)) {
ReHashPassword(hashedPassword, providedPassword);
return PasswordVerificationResult.Success;
}
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
}
In the code snippet above, notice in the call to GetSHA1Hash that I don't have a second parameter to pass in.
How could I go about doing my legacy salted password check? In the new system I suppose I could make the hashed password stay as the result of the username + id. However, since the implementation of ASP.NET Identity doesn't seem to cater towards that, what would be my best option?

The way the modern salts are stored is that they're just added to the hashed password value (see this: http://brockallen.com/2012/10/19/password-management-made-easy-in-asp-net-with-the-crypto-api/). So you might have to modify (ahem hack up) the UserManager to load the salt from the separate column and pass it into the password hasher as part of the hashed password.

I found this article; it has code samples extending the UserManager and using a crafted PasswordHasher which does exactly what you want.

Related

Asp.net Identity password hashing

The new ASP.net Identity project has brought some useful code and interfaces for website security. To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.
IPasswordHasher interface in ASP.net Identity
namespace Microsoft.AspNet.Identity
{
public interface IPasswordHasher
{
string HashPassword(string password);
PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword);
}
}
Is it possible to use password salting for more secure encryption in ASP.net Identity and via this interface?
HEALTH WARNING for the below answer: Know which version of ASP.Net Identity you are using. You should refer to the source code directly if it is one of the newer versions from the github repository.
As I write this, the current version (3.0.0-rc1/.../PasswordHasher.cs) of the password handler is significantly different to the below answer. This newer version supports multiple hash algorithm versions and is documented as (and may change further by the time you read this):
Version 2:
PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
(See also: SDL crypto guidelines v5.1, Part III)
Format: { 0x00, salt, subkey }
Version 3:
PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
(All UInt32s are stored big-endian.)
The original answer is still valid for the original version of ASP.Net Identity, and is as follows:
#jd4u is correct, but to shed a little more light which wouldn't fit into a comment for his answer:
Microsoft.AspNet.Identity.PasswordHasher : IPasswordHasher already salts for you,
more importantly it uses Rfc2898DeriveBytes to generate the salt and the hash,
which uses industry standard PBKDF2 (SE discussion here, OWASP recommendation for PBKDF2 here).
The default Microsoft.AspNet.Identity.UserManager<TUser> implementation uses Microsoft.AspNet.Identity.PasswordHasher as a concrete IPasswordHasher
PasswordHasher in turn is a really simple wrapper for (ultimately)System.Security.Cryptography.Rfc2898DeriveBytes
So, if you are going to use Rfc2898DeriveBytes, just use PasswordHasher - all the heavy lifting is already done (hopefully correctly) for you.
Details
The full code that PasswordHasher (currently) ultimately uses does something very close to:
int saltSize = 16;
int bytesRequired = 32;
byte[] array = new byte[1 + saltSize + bytesRequired];
int iterations = SOME; // 1000, afaik, which is the min recommended for Rfc2898DeriveBytes
using (var pbkdf2 = new Rfc2898DeriveBytes(password, saltSize, iterations))
{
byte[] salt = pbkdf2.Salt;
Buffer.BlockCopy(salt, 0, array, 1, saltSize);
byte[] bytes = pbkdf2.GetBytes(bytesRequired);
Buffer.BlockCopy(bytes, 0, array, saltSize+1, bytesRequired);
}
return Convert.ToBase64String(array);
"Is it possible to use password salting for more secure encryption in
ASP.net Identity and via this interface?"
Yes, the interface is provided for the new implementation of PasswordHasher already present in Core framework.
Also note that the default implementation is already using Salt+Bytes.
After creating custom PasswordHasher (say MyPasswordHasher), you can assign it to UserManager instance like userManager.PasswordHasher=new MyPasswordHasher()
See one example of such IPasswordHasher
To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.
For implementing alternate system from EF,
- You shall implement all Core interfaces.
- IPasswordHasher implementation is not required. PasswordHasher is already provided in Core framework as it's implementation.
I ran into an issue while updating from Membership to AspNet.Identity. The Rfc2898 hashes are different from those used before. That's for good reason, but changing the hashes would require all users to reset their passwords. As a solution this custom implementation makes it backwards compatible:
public class MyPasswordHasher : PasswordHasher {
public FormsAuthPasswordFormat FormsAuthPasswordFormat { get; set; }
public MyPasswordHasher(FormsAuthPasswordFormat format) {
FormsAuthPasswordFormat = format;
}
public override string HashPassword(string password) {
return FormsAuthentication.HashPasswordForStoringInConfigFile(password, FormsAuthPasswordFormat.ToString());
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) {
var testHash = FormsAuthentication.HashPasswordForStoringInConfigFile(providedPassword, FormsAuthPasswordFormat.ToString());
return hashedPassword.Equals(testHash) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
}
}
Once you create your UserManager instance just set the hasher:
Usermanager.PasswordHasher = new MyPasswordHasher(FormsAuthPasswordFormat.SHA1);
The code complains that the HashPasswordForStoringInConfigFile method is deprecated, but that's fine as we know that the whole exercise is to get rid of the old technology.

System.Web.Services : is there password property in Context.User.Identity

just a small query
i m using .net web service and created simple login method
[WebMethod]
public bool Login(string sUsername, string sPwd)
{
if (sUsername == Context.User.Identity.Name && **sPwd == "123456"**)
{
FormsAuthentication.SetAuthCookie(sUsername, true);
return true;
}
else
return false;
}
is there any password property like "Context.User.Identity.Name" . or any other alternative
Please suggest if i am missing something
Your approach doesn't make sense. The Context.User is set by the Forms Authentication module which relies on the information from the forms cookie. You, on the other hand, try to use the information to acually ISSUE the cookie.
This means that you effectively need the cookie to issue the cookie. This won't work.
Try to rethink the approach - you probably need an external data source, like a database or something, to validate your users against. In the database you will have both usernames and their passwords stored somehow.

Require stronger password for some users based on roles

I have a MVC 3 app. There are mainly two zones regarding security. The first one is mostly to prevent public access, but not really sensitive information. Password strength might be weak since there is not really much harm to do either.
Second zone(Area) is restricted. user must apply for access. If user gets access it gets a certain role(s). So each controller method autorizes the user based on that role.
I want these users to have to change password to a strong password on the next logon before they can go further and access the restricted content.
Example:
User A applies for access.
Access is granted. The password policy for
that user is changed as long as it has access. They MUST
change their password on the next logon, and they cannot change back
to a weaker password as long as they have that role.
Is there any secure way to implement this using the ASP.NET?
Update
I've actually used Chris proposed solution and it works, but to handle the verification of the password itself I actually got some inspiration from Micah's proposed solution too. However, it turns out that overriding MembershipProvider.OnValidatingPassword does imply also having to implement 10 + abstract methods that I really do not need to solve this.
A better solution in my eyes was hooking on to the Membership.ValidatingPassword EVENT. I do this inn App_Start, then I implement my own password validation in the event handler and that solved my problem.
Just to share the solution with you i present it here, toghether with Chris solution this solved my problem and hopefully for someone else too:
void App_Start()
{
//To do custom validation on certain passwords set new event handler
Membership.ValidatingPassword += Membership_ValidatingPassword;
}
private void Membership_ValidatingPassword(object sender, ValidatePasswordEventArgs e)
{
//If the user is a new user, we let registration happen without strong password
if (e.IsNewUser) return;
MembershipUser membershipUser = Membership.GetUser(e.UserName);
Guid userId = Guid.Parse(membershipUser.ProviderUserKey.ToString());
//First check if the pwd is strong enough to be flagged, if so we flag it
//using regex to validate the password (20 char, 2 uppercase so on)
if (MyValidationClass.IsStrongPassword(e.Password, 20, 2, 4, 1))
{
//if the user does not already have a flag we set one
MyValidationClass.SetStrongPasswordFlag(userId);
}
else
{
//If the user needs strong pwd, we cancel the operation and throw exception
if (MyValidationClass.NeedsStrongPassword(e.UserName))
{
e.FailureInformation =
new MembershipPasswordException("Password does not satisfy reqirements!");
e.Cancel = true;
}
else
{
MyValidationClass.RemoveStrongPasswordFlag(userId);
}
}
}
You could write your own Authorize Attribute to accommodate both. You simply need to then use it on the relevant sections of your application:
For example:
public class HasChangedPasswordAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
UserRepository repo = new UserRepository();
var user = repo.GetCurrentUser();
bool hasSecurelyChangedPassword = user.HasSecurelyChangedPassword;
return hasSecurelyChangedPassword;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult("/Account/ChangePassword");
}
}
The above will check that the user has securely changed their password. If not it will redirect them to a new page in which to change their password. Once they change it, set the flag as changed.
You can then use it like this:
[HasChangedPassword]
[Authorize(Roles="SuperRole")]
public ActionResult MySecureAction()
{
...
}
You could obviously integrate both of these attributes into one, but for the sake of showing the example they are seperated above.
you will need override the MembershipProvider.OnValidatingPassword
http://msdn.microsoft.com/en-us/library/system.web.security.membershipprovider.onvalidatingpassword.aspx
Probably a simpler method would be check the strength of the password on the client-side when you user is attempting to enter a new password. Check out this list for some examples using JQuery.
In regard the transaction of upgrading and resetting the password, that's something your code can handle, i.e. a flag in the users table that redirects the user to a new registration page. But when they set the password (and presumably it matches the appropriate strength) it can then be submitted...

How do you get the UserID of a User object in ASP.Net MVC?

I have some tables that have a uniqueidentifier UserID that relates to aspnet_Users.UserID. When the user submits some data for those tables, since the controller method has an [Authorize] I get a User object. I can get the username with User.Identity.Name, but how do I get the UserID to be able to establish (the ownership) relationship?
It seems you cannot get it from the User object but you can get it this way:
Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
Here is the solution:
Include:
using Microsoft.AspNet.Identity;
Then use extension methods:
User.Identity.GetUserId();
Firstly, this answer is not strictly an MVC answer, but an ASP.NET answer. The fact that your site is MVC is irrelevant to solving the problem, in this case.
Hmm. I'm not very sure how you are handling your users in your system but it sounds like you using the (very evil) asp.net membership provider that comes out of the box with .net. This is hinted by the fact that you said
aspnet_Users.UserID
UserID is a uniqueidentifier (read: GUID).
With the default forms authentication system, which uses the default FormsIdentity, it only has a single property called Name (as you correctly noted). This means it has only one value where to place some unique user information. In your case, you are putting Name/UserName/DisplayName, in the Name property. I'm assuming this name is their Display Name and it is unique. Whatever value you are putting in here, it HAS TO BE UNIQUE.
From this, you can grab the user's guid.
Check this out.
using System.Web.Security;
....
// NOTE: This is a static method .. which makes things easier to use.
MembershipUser user = Membership.GetUser(User.Identity.Name);
if (user == null)
{
throw new InvalidOperationException("User [" +
User.Identity.Name + " ] not found.");
}
// Do whatever u want with the unique identifier.
Guid guid = (Guid)user.ProviderUserKey;
So, every time you wish to grab the user information, you need to grab it from the database using the static method above.
Read all about the Membership class and MembershipUser class on MSDN.
Bonus Answer / Suggestion
As such, i would CACHE that result so you don't need to keep hitting the database.
... cont from above....
Guid guid = (Guid)user.ProviderUserKey;
Cache.Add(User.Identity.Name, user.UserID); // Key: Username; Value: Guid.
Otherwise, you can create your own Identity class (which inherits from IIdentity) and add your own custom properties, like UserID. Then, whenever you authenticate (and also on every request) you can set this value. Anyway, this is a hard core solution, so go with the caching, right now.
HTH
User.Identity is an IPrincipal - typically of type System.Web.Security.FormsIdentity
It doesn't know anything about UserIDs - it's just an abstraction of the concept of an 'identity'.
The IIdentity interface only has 'Name' for a user, not even 'Username'.
If you're using MVC4 with the default SimpleMembershipProvider you can do this:
WebSecurity.GetUserId(User.Identity.Name) // User is on ControllerBase
(Where WebSecurity is in the nuget package Microsoft.AspNet.WebPages.WebData in WebMatrix
You can also use
WebSecurity.CurrentUserName
WebSecurity.CurrentUserId
(if you're using ASPNetMembershipProvider which is the older more complex ASPNET membership system then see the answer by #eduncan911)
If you are using the ASP.NET Membership (which in turn uses the IPrincipal object):
using System.Web.Security;
{
MembershipUser user = Membership.GetUser(HttpContext.User.Identity.Name);
Guid guid = (Guid)user.ProviderUserKey;
}
User.Identity always returns the state of the current user, logged in or not.
Anonymous or not, etc. So a check for is logged in:
if (User.Identity.IsAuthenticated)
{
...
}
So, putting it all together:
using System.Web.Security;
{
if (User.Identity.IsAuthenticated)
{
MembershipUser user = Membership.GetUser(HttpContext.User.Identity.Name);
Guid guid = (Guid)user.ProviderUserKey;
}
}
Best Option to Get User ID
Add Below references
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;*
public myFunc()
{
.....
// Code which will give you user ID is
var tmp = User.Identity.GetUserId();
}
If you are using your own IPrincipal object for authorization, you just need to cast it to access the Id.
For example:
public class MyCustomUser : IPrincipal
{
public int UserId {get;set;}
//...Other IPrincipal stuff
}
Here is a great tutorial on creating your own Form based authentication.
http://www.codeproject.com/KB/web-security/AspNetCustomAuth.aspx
That should get you on the right path to creating an authentication cookie for your user and accessing your custom user data.
using System.Web.Security;
MembershipUser user = Membership.GetUser(User.Identity.Name);
int id = Convert.ToInt32(user.ProviderUserKey);
Its the ProviderUserKey property.
System.Web.Security.MembershipUser u;
u.ProviderUserKey
Simple....
int userID = WebSecurity.CurrentUserId;
Usually you can just use WebSecurity.currentUserId, but if you're in AccountController just after the account has been created and you want to use the user id to link the user to some data in other tables then WebSecurity.currentUserId (and all of the solutions above), unfortunately, in that case returns -1, so it doesn't work.
Luckily in this case you have the db context for the UserProfiles table handy, so you can get the user id by the following:
UserProfile profile = db.UserProfiles.Where(
u => u.UserName.Equals(model.UserName)
).SingleOrDefault();
I came across this case recently and this answer would have saved me a whole bunch of time, so just putting it out there.

Custom IPrincipal together with WindowsAuthentication

Is there any good way of combining ASP.NET Windows Authentication with a custom IPrincipal/IIdentity object? I need to store the user's email address and have done so for Forms Authentication using a custom IIdentity/IPrincipal pair that I added to the Context.CurrentUser during the AuthenticateRequest event.
How would I best go by to accomplish this using WindowsAuthentication?
Maybe you could create your "ExtendedWindowsPrincipal" as a derived class based on WindowsPrincipal, and just add your extra data to the derived class?
That way, your ExtendedWindowsPrincipal would still be recognized anywhere where a WindowsPricinpal is needed.
OR: since you're talking about using Windows Authentication, you're probably in a Windows network - is there an Active Directory or a user database somewhere, where you could look up your e-mail address that you're interested in instead of storing it in the principal?
Marc
I ended up refactoring my initial solution into replacing the Principal instead of the Identity as I originally thought. Replacing the Identity proved troublesome, since i ran into security problems when creating an instance of a new extended WindowsPrincipal.
public class ExtendedWindowsPrincipal : WindowsPrincipal
{
private readonly string _email;
public ExtendedWindowsPrincipal(WindowsIdentity ntIdentity,
string email) : base(ntIdentity)
{
_email = email;
}
public string Email
{
get { return _email; }
}
}
In my Authentication module i replaced the principal on the HttpContext like this:
var currentUser = (WindowsIdentity)HttpContext.Current.User.Identity;
HttpContext.Current.User =
new ExtendedWindowsPrincipal(currentUser, userEmail);

Resources