Admin site: create other users without logging in


I am building an admin area where an admin can create other users giving a username and password.

1)On the client, Accounts.createUser logs the user in automatically so I cannot use it
2)So far I added a method on the server that creates the user for me and it works. However if I do it this way, how do I handle the client sending the password to the server? By default if I am not mistaken, it will be in plain text, not hashed, so it should be unsafe, correct?
3)I have the same problem if, later on, I want the admin to change another user’s password. I cannot use changePassword on the client, because it is only for the loggedin user. I cannot use setPassword on the server, without before sending the password in clear text over the wire in a method.

In general I see that the Accounts API handle the password security and I like that, but it seems that all its client methods are assumed to be for the loggedin user, and to use the server methods that would fix my problem I still need a way to handle the password transfer safely.

What is the best way to do that?

1 Like


I don’t really understand your problem: where do you want to generate the password? Clientside, or Serverside?
If you do it clientside, clearly, you need to send it to the server some way. But how would the user know the changed password?




it would be clientside.
The idea is that the admin create other user accounts, sets an initial password, and when those new users login, they change it.
The admin would be in direct communication/contact with the new users, so he could simply tell them the initial password.
Also the admin has full control on those accounts, as he has the power to reset/change those users’ passwords if there’s need, and delete those users as well.

I cannot use the “noInitialPassword + sendEnrollmentEmail” trick described in the meteor guide as I need those accounts to be username-based, not email-based.

Ah, I see. Why not use: Accounts.createUser in combination with Accounts.setPassword?
That would not send an enrollment mail, and set the password?

Accounts.setPassword is on the server. In order to use it, I need to have the password somehow on the server, and if it needs to be specified by the admin in the UI, the problem is always the same, how do i send the password to the server in a safe way without using the Accounts client-side API ?

I tried to look into the Accounts’ source code, and the client-side API use Accounts._hashPassword before sending it on the wire. I thought about using this function in my own client-side logic, but I am not sure what will happen if on the server I call Accounts.createUser passing a password that has already been hashed by the client?

If you are worried about sending the password: do you use https? In that case, unless you are really into deep waters (ie: working for a government or something) I would not worry about sending the password. If you use https, it will be encrypted anyway…

I do use https, and I would agree with you that https should fix it, however I try not to rely on one single layer for security.
Maybe I am over-worrying, but I like the thought that even if something goes wrong (for some reason the app gets served in http instead of https for example) I still protect the most sensitive data.

After looking at the source code, I realized that it is actually possible to call Accounts._hashPassword(password) on the client before sending it to the server.

On the server then you can invoke Accounts.createUser or Accounts.setPassword with the hashedPassword, and the accounts package will handle it anyway.
So I think that’s the best solution that I can find.

That’s adding a layer of “security” into your setup which, basically, is useless to deter a determined attacker.

It’s something that sounds like security but basically isn’t.

Just one aspect on how this does not make you any more secure: How will the user actually login now?

Another aspect: Quite a lot of attacks rely on injecting code onto the target page instead of doing a MITM attack.

I don’t understand these remarks.

1)the user will login as always with the Accounts api that itself hashes the password as well before sending it to the server. And it simply works. No need to do anything different than in a normal flow.
2)“Another aspect: Quite a lot of attacks rely on injecting code onto the target page instead of doing a MITM attack.” I really don’t understand how this comment is relevant with my solution.
I didn’t claim that now my app is unattackable in any possible way. I claimed that now I am not transferring the password in clear over the wire, https or not.
If the attacker manages to execute arbitrary code on the user’s client you are already screwing up in the first place and it is simply not relevant to the topic of this discussion.

Moreover I am simply doing what MDG did as well in their accounts package, actually reusing the same code (Accounts._hashPassword) that they use.
They provided us with a standard set of APIs. I think it’s a proper mindset to have that if you are going to create a custom method to replace one of those APIs, you try to use the same security measures that they took themselves.

“Security” is not one single thing. Attackers can attack a software in multiple ways and in multiple layers, and therefore a proper security mindset should try to put some defenses in multiple ways and multiple layers.
Having an additional layer, if there’s no performance and no drawbacks involved, is never a bad thing, even if by itself doesn’t shield you from all attacks.

Listen, if https is compromised then there’s no point in hashing or other things you’re doing. Yes, you’re transmitting a hash now.

And? Now the attacker can login with the hash because the hash is now your password.

You have won precisely nothing.

Yes, if https i compromised the attacker can login on my app.
But at least it won’t know the original password, so if a user is reusing it in multiple apps/sites (and most users are) you didn’t expose it. Or at least not as badly as if it would be clear text.
Call it a small win if you want, but for me it’s still a pretty significant one.

If the attacker is in a position to
a) compromise https and
b) read your traffic
then the attacker will also most likely also be able to manipulate the traffic and insert anything he wants. Like clientside scripts which snatch the passwords directly from the textfield.

Even if they can, and they probably can, it still doesn’t mean that I shouldn’t try to do everything I can to make it more difficult for them.
Especially considering it doesn’t cost me absolutely anything in terms of performance, development time or anything else.

Again it looks like you are pretending that im saying "now that I dont send the password in clear text my app will be inattackable:.

That’s not what I am saying.
I have many other layers of security in place. I use only https. I sanitize any input from the users, and output that i render on the page. I check for injections. I check every single publications I do, I filter all the fields I publish and so on and on.
And even with more checks security is never granted, period. Basically every software in the world is attackable in a way or the other, and new ways are getting discovered every day.
Still I don’t get what’s so bad in adding as many protections as possible if you can.

I don’t see where that is actually making it more difficult for an attacker.

It makes it more difficult for you.

Would like to see someone experienced chime in on this one here. I’m too hashing users’ passwords already client side with Accounts._hashPassword() when calling a method that creates users on server side along with a password. Mainly because of the very common concern over transmitting passwords in plain text over the wire. Don’t really like to use Meteor’s internals directly, but since the Meteor team decided that hashing passwords client side is important enough to implement it and they emphasize it in the guide as well, I assumed it would not make sense for me to not follow suit. Regardless of https. My general approach to security is that it is complex and therefore I try to stay as close to standard solutions as possible and not trust my own creativity.


Basically you wrote what I had in mind from the start, and the reason I opened the topic in the first place

Difficulty for me: 1 line of code literally
Difficulty for them: arranging the injection on the page, the client script and all the rest.

If you don’t see how is more difficult for them than for me, I honestly think you simply want to be right in the discussion and there’s no point discussing it further.

No, I simply don’t subscribe to Cargo Cult security, sorry.

Difficulty for them: arranging the injection on the page, the client script and all the rest.

Not true. Your original assumption was that https is compromised. Anything after that is child’s play.

Your original assumption was that https is compromised.
Not mine.
There are several scenarios for which https might not be a problem at all. Maybe your server configuration serves both http and https and you don’t realize immediately.
Maybe there was a problem in your configuration management on the servers and for a while https was switched off.
Maybe there’s simply a bug in one layer that could be even out of your control that exposes the traffic under certain conditions.
There’s just no way to predict all the possible ways your app can get compromised in a way or the other.
The password will be compromised under scenario 1 or 2 or 3? Maybe there’s a scenario 4 in which it won’t be compromised thanks to this change. Maybe not.
All it costs is one line of code.

If we would be hear talking about a change that costs significant performance losses, or have other big drawbacks, I would consider it. But this is not the case here.

Call it Cargo Cult security, or call it whatever else you want, honestly, I really just don’t care.

If you can inject code on a client to steal a user password, send it to a server of yours (that you need to configure, and probably behind a few proxies to try to be less reachable i guess), trying to avoid being detected and people realizing what you are doing, in less than one line of code consisting of one function call than you are right. But again, you are not, and as I mentioned before: