Accounts-password difficulties enforcing password strength

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:

  1. 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.
  2. 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)
  3. 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.
1 Like

Hi,

I’m not sure why you are “programming” this yourself. I basically got the interaction you got, without programming anything? I added this code:


AccountsTemplates.removeField('password');                                      // IC153
AccountsTemplates.addField({
    _id: 'password',
    type: 'password',
    placeholder: {
        signUp: "Minimum 8 characters length."
    },
    required: true,
    minLength: 8,
    re: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}/,
    errStr: 'Minimum 1 digit, 1 smallcaps letter en 1 caps letter.',
});

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?

regards,

Paul

1 Like

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.

1 Like

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.

1 Like

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

2 Likes

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.

What package defines AccountsTemplates?

Hi @mvolkmann,

I’m not sure, but would assume accounts-ui, as that defines the UI for this function.

regards,

Paul

I’ve looked there and also done lots of googling. So far I haven’t found information on how to do this.

I think I got it from here:

and followed the instructions from there…

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.

Any thoughts on this?

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?

Good idea. Added to this feature request Accounts Password Setting Server Hooks.

2 Likes

I was digging back into this, and this solution still doesn’t really work entirely. Yes, you can add your own Meteor methods to validate and make Accounts function calls on the server, but all the original Accounts methods are still available on the client.

Someone with some savvy can just call the native Accounts methods from the client at any time.

Until those are patched up and/or hooks are added, there’s no real way to enforce any server-side password requirements in Meteor. If you’re using the native accounts-password package.

EDIT: If you roll some of your own methods in Meteor, could you then trash/overwrite some of the native Meteor Accounts client methods somehow in a Meteor.startup() block? Besides actually editing the package?

At one point, I was on Github and these forums going on about this password length DOS issue.

Upon revisiting this and having a bit more experience with Meteor, the Accounts.setPassword is a server-only method for use by your own server code. So a malicious actor could never call this from the client with an overly-long password.

They can still call the client methods but those all hash on the client which would not DOS your server thankfully. So this is a non-issue.

It’s still an issue you can’t control your app’s password rules in Meteor, but we all know that by now. :stuck_out_tongue_closed_eyes:

Remove the package from Meteor. You only need the base Accounts package if you create your own registration and login handlers