Password Blacklists - ruby-on-rails

I've got a blacklist of passwords that I don't want Users to be able to select when they're creating their account or changing there password in my Rails app.
I want this to be in a database table rather than a YAML file.
How can I refer/check if the user's submitted password exists in this list? What's a way to do it?
It doesn't feel right that I'd need o create an ActiveRecord Model for it etc.

How can I refer/check if the user's submitted password exists in this list? What's a way to do it?
If you encrypt your user passwords (like I hope you do), it's a little bit challenging to perform this check (in fact, that's exactly one of the purposes of salt encryption passwords).
You will need, for each user in your database, loop each password, encrypt it using your current encryption strategy and match the result with the encrypted string stored in the database for the user. If they do match, it means the user is using one of those passwords.
And that's for already stored passwords.
I don't want Users to be able to select when they're creating their account or changing there password in my Rails app.
This is easier than previous step. When the user is signin up or updating the password, just compare the user-entered unencrypted password with the list you have. If there is a match, return a validation error.

Related

Changing database structure and migrating password hashes

I currently have a site (Rails 4.1, ActiveRecord, Postgres) where a visitor can log in to one of multiple models — for example, a visitor can create an account or login as a User, Artist, etc. Each of these models have a password_digest column (using bcrypt and has_secure_password).
Now we want to move to the site to a unified login system — everyone creates and logs in as a User, and a User can belong to an Artist and the other models we have.
I think it makes sense to directly use the password_digest column in the User table, rather than looking across all the existing models. This means we'll have to create new entries in the User table and copy the password_digests into them.
Can this be safely done, and would everyone be able to login with the password they already have? I've tried playing around with password_digests in the Rails console (copying digests to known passwords and assigning them to other entries) and it appears to authenticate correctly … are there any downsides to doing this?
There's no uniqueness constraint on passwords (i assume) and so it doesn't matter if the passwords are the same between different User accounts (in the resulting table, with all the Artist etc records copied in). There's no safety issues with copying the data from one table/column to another: there's nothing magical about the password_digest value, it's just a text string. As long as you carry on using the same encryption method then the crypted password you generate to test on login should still match the saved value.
You may have a problem with usernames though, if they are required to be unique: what happens if you have an existing User and an existing Artist who have the same username? Is one of them going to have to change?

SimpleMembership Roles with no Username - is it possible?

Users in my database have a non-unique display name; the only unique identifier is the UserId.
Normally, I would add a user to a Role using the following:
Roles.AddUserToRole(user.Username, role);
But now I don't have usernames, so I need to re-think all work related to Roles.
One messy option I can think of is to copy the Id of every user into the Username field just to satisfy SimpleMembershipProvider... though I'd rather somehow use extension methods to handle this if it's even remotely advisable and possible to do so... just so I don't have to clutter my Users table with a bogus column.
Any help here would be much appreciated.
Update:
Even if I copy the userId to the username column to get SimpleMembership working, I still need a username to create the user:
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, etc)
So I'm at a loss of what to do, aside from rolling my own Membership.
Update again: I just realized I can pluck my email field and just use the Username column to store unique email addresses. I'm still interested in hearing how else this could be addressed.
You need something unique the user can enter to identify themselves during authentication, whether it is a username they user came up with, an email address, PIN, etc... Having the user remember a number generated as the unique identifier for the UserProfile does not seem like a good user experience. So whatever is used to uniquely identify that user, that is used during the log in process by the user, can be stored in the username column, if you do not want to add any additional columns. From the latest update to the question it looks like email address is being used to identify the user and you could store this in the username column without issue.
Adding columns to the UserProfile is easy to do and I would not shy away from it if it provides a better user experience and security. For example, if you want to capture a display name to display on the web site or in any communications with users you could add an email column and tell SimpleMembership that you want to use that to identify the user by changing a parameter in the WebSecurity.InitializeDatabaseConnection Method. You would change the parameter userNameColumn to be the name of your email column.
yes, either use the Ids as username or if the email is unique as username.
It is not a messy way btw with this situation. I would go with the id, if no one will eversee the userId.

Migrating existing authentication to has_secure_password

In my application, I have two different user accounts. The old account type was using a custom built authentication system. The newer one implements has_secure_password. Now I'm ready to move the old account type to the same system. In the database, that user type has a hashed_password column.
I have it working so that creating new users works, and they can login just fine on the new system. The problem is that I need existing users to be able to migrate their passwords from the hashed_password to password_digest. What is the best way to go about doing this?
It's possible, but you'll have to juggle a bit. Let's say you've used MD5 to hash passwords before you wanted to migrate. Make sure you have made a backup before you migrate :) Add a boolean column migrated_password to the database, default true. In your migration, do something like User.update_all(migrated_password: false) for existing users.
Use the current MD5 hashes as input for the has_secure_password function. Alter your login code to handle two paths, depending on the value of the migrated_password column. If the password is migrated (or the user registered after the migration), you use has_secure_password straight out of the box.
If it isn't, you hash the password with MD5 before feeding it to the authenticate method. If the login is successful, change the password of that user with the input password from the params and update the migrated_password column to false (wrap those two actions in a transaction).
After a certain amount of time you can delete the the migrated_password column and the migration code, and let users use your password reset functionality if they still need access but haven't migrated in time.

Safe way to retrieve secret keys

I'm working on an app that has a red button. What that means is that every client account has two (secret) keys that are automatically generated. When someone enters those keys on a special (public) page, a certain process will be set in motion. The process is not critical, but
That's all taken care of, the keys are automatically generated on user account creation, stored encryped in the database and are shown to the user once so he can distribute the keys as he sees fit. He can of course reset the keys if he wants to.
The thing is, some clients keep forgetting the keys. Our solution is to reset the keys and redistribute the new keys, but for some clients that's just not practical. I'd like to offer the option of retrieving the keys without resetting them.
My idea was to be able to decrypt the keys using the user's password, meaning that the already logged in user would have to enter his password again, which was used to encrypt the keys and is now used to decrypt them. I'm just not sure how that would technically work (is there an encryption/decryption algorithm that I could use?) and whether there's anything I should consider before employing such a technique.
Does anyone have any ideas on this? Maybe even a better suggestion?
You want to check out ciphers like AES.
I'd check out this gisthub example on how to use Ruby and AES for encryption and decryption.

LINQ to SQL - converting temporary users to real users

In creating a new ASP.NET MVC application, I have an issue with the approach I'm using to store user-created data for temporary users who have yet to create an account which I then try to convert to a real user. That probably doesn't make much sense, so let me explain:
A visitor to the site can enter profile settings before being made to register with a username, password, etc.
I'm creating database entries via LINQ to SQL for a new user in this case, using the Request.AnonymousID value as a temporary username.
When the user chooses to register, I need to 'switch over' the relevant database records to use the newly entered username instead of the temporary one.
The problem is that when I try to update the record I can't because the username is the primary key, so I'm forced to delete the record and add a new one...
I can probably persevere with this, but I think I might just be going about this in completely the wrong way and wondered if anyone could suggest a better way to allow visitors to store information before they've registered and have that carry over when they do.
I know about profiles but want the profile information to be available to other visitors. I also know that I can create an anonymous profile but it seems like I should be able to keep the data model out of the web.config file.
I would suggest having an independent primary key for the table with your custom user data.
And then have fields like RefAnonymousId and RefUserId to relate that user data to the anonymous user and the registered user, respectively.
For example:
TABLE UserData
(
UserDataID int IDENTITY(1,1) PRIMARY KEY,
RefAnonymousId uniqueidentifier,
RefUserId uniqueidentifier,
... (data fields),
(maybe also unique keys on RefUserId and RefAnonymousId)
)
That way you will also be able to identify the user when the user is logged out and maybe automatically log the user in...

Resources