I’m building a user registration and password reset interaction with the accounts-password package and having some problems, hoping someone here can help. I’m trying to build the following interaction:
User signs up for an account, they get an email sent to them via Accounts.sendEnrollmentEmail with a link to click to create their password and complete account setup.
When the user enters their new password, I want the server side to validate the password strength (min length, requires at least on special character, etc)
when the password is strong enough and the account is created, the email address for their account completed and marked as verified
Number 2 doesn’t seem possible currently, I’m hoping I’m just misunderstasnding how to use accounts-password. My is the following:
For # 2 above, the function Accounts.resetPassword(token, newPassword) with the token the user received in their email is only available on the client. Because of this, it’s impossible to do validation on the new password on the server. Why is this not available on the server as well? It would be great if similar to Accounts.validateNewUser there was a Accounts.validateNewPassword() method, so that I could trust calling Accounts.resetPassword(token, newPassword) from the client will have its password strength enforced.
to the file: both/accounts/config.js and that did it for me, as far as configuration was concerned. For the rest, it worked as I expected. What exactly are you missing the existing workflow that you feel the need to really program?
From what I can tell that relies on Blaze, Im using Vue and don’t want that extra dependency in my bundle. That also appears to only do client side password validation, I’m asking for server side validation. And finally, I want to keep all UI state in Vuex as a central state management solution for consistency, including UI validation errors, which does not work if I use a pre-built UI solution.
Server-side validation requires that you send the requested password as clear-text over the wire, so you have to consider which is the highest risk:
as clear text, anyone ‘in-the-middle’ can potentially snoop on the password.
client-side validation hashes the password before sending it to the server, so it’s harder for man-in-the-middle attackers to get the original password.
The only risk with client-side validation, is that a user who knows his way around Meteor and JS is able to set a password for himself with less characters than you would prefer. In the end, none of the actual passwords are stored, everything is hashed and bcrypted.
Any password form should be using SSL, so MITM attack isn’t an issue. I just want to enforce strong passwords in a financial application, even if client side validation fails for some reason. But the issue is I can’t do it on the server because the resetPassword(token, new password) with the token from their email is only available on the client
You could implement it yourself: the callback you set on Accounts.onEnrollmentLink on the client gets the token from the email. Make a custom server method you call from the client with the token and the desired password. The server method checks the token from the client with the server’s version ( it is stored in the user’s profile) and validates the password. If all is ok, the server sets Accounts.setPassword, and notifies the client.
I had a security researcher email me that Meteor’s accounts-password allows extremely long password lengths, which can lead to DOS attacks due to the server over-working to hash the long passwords. I’ve reviewed the code in accounts-password and it doesn’t seem like it limits the password length in anyway before hashing it with SHA256.
It looks like Accounts.setPassword(userId, newPassword, [options]) doesn’t hash on the client, but on the server.
It seems like this could be a good candidate for a quick improvement in the accounts-password package by adding a setting for maximum password length by default. Would you mind opening a feature request for it in github?