The God Login
blog.codinghorror.com
blog.codinghorror.com
Personally I love the Facebook approach. Facebook just accepts passwords with caps lock inverted, so you never have the problem in the first place. No need to display a message to the user.
Link: http://www.zdnet.com/article/facebook-passwords-are-not-case...
I think he means doing it on the server, i.e. checking the password as-is, if that doesn't work, then check it with case inverted.
This is important because if you want to decode a hashed password using a rainbow table for example, you still have to hash the entire keyspace, not just half of it.
Edit @sp332: Exactly. That was my point.
var caps = null;
passwordField.onkeypress = function(e) {
if (caps !== false) {
var s = String.fromCharCode(e.keyCode || e.which);
caps = s.toUpperCase() == s && !e.shiftKey;
}
};
loginForm.onsubmit = function(e) {
if (caps) {
passwordField.value = invertCase(passwordField.value);
}
};For n character alphabetic values, it reduces the keyspace from 52^n to 26^n.
Which is widely regarded as bad security practice because your users' passwords can be compromised by an attacker getting read-only access.
[EDIT] Well, good thing I used "almost", since I was wrong: of course, case-inverting the password and hashing the result could also be done client-side, silly me!
[EDIT'] Answers pointing out that you always have access to non-hashed passwords, and I believe this is wrong. When the user submits their password, it SHOULD be hashed client-side and only the hash SHOULD be sent to you.
In that case I guess I have to wonder what the point is? Why store three hashes as opposed to just upper-casing the plain-text before hashing? You end up storing fewer variations, and it makes no functional security difference to the front-end (since any attacker would just .toUpperCase() their inputs anyways)?
At least best I can reason.
There is no need to store the password in plain text in any form.
Facebook, and any other company you'll log in to, requires a non-hashed password at some point to check against the hash. You need a cleartext password at some point, otherwise the user can't send anything to you.
The best practice for security is to not store passwords in cleartext. You can certainly perform extremely limited actions on passwords in cleartext (like hash checking), and you inevitably have to.
Which brings me to my overall point - as the Facebook security team has explained before on their whitehat page, you do not practically reduce security by allowing caps lock inversion to check a hash.
What you're saying about Facebook having an abnormal process also isn't true either - Facebook does one of two things, both of which are secure:
1. Stores two hashes for each password, one the real password and the other the case inverted, or
2. Checks a password against a hash, and inverts the case and checks again if it fails.
There is nothing about this which is different from normal password transmission in cleartext, and Facebook doesn't store the cleartext password you send them.
EDIT to your EDIT:
No, no no no no, no. Don't do clientside things like that. Allowing a user to directly manipulate something as major as whether or not their password is hashed before it is sent to you is bad. It doesn't even matter that it's just them hacking themselves; it's just bad form to put that in their browsers' hands. Plus, a stored cross-site scripting error that went viral on the login page pre-auth could screw your password database, leading to a layup for mass cleartext password compromise. Or in a worse scenario, you're giving a user direct write access (and then maybe reads) to the password database.
It's much safer to do the industry best practice of destroying cleartext sensitive information upon successful hash.
Say no to clientside security. There are arguments for hashing clientside, but they can all be summed up by "You shouldn't let people potentially sniff users' passwords" - if you implement TLS/SSL correctly, this won't be an issue and the cleartext password will exist briefly, then get destroyed.
The one other argument is that someone could compromise the server handling the hashing process and write a script watching all the passwords. But this isn't a valid concern - if someone has backdoored your login server, it no longer matters if passwords are cleartext for the damage they'll do. The level of difficulty you introduce by having passwords hashed originally becomes moot at that point.
Finally, consider that a client-side hash of a password sent to a server becomes the effective password for that user, not the hash of the password. This means that, effectively, if no other action is done at the server, you're actually then storing the password in plaintext. If a user was MITM'd while sending the password, the hash can now be sent directly to the server in place of the user's password, because it is the de facto password.
The bottomline: client-side hashing offers no real addition to overall security posture under TLS/SSL, and removes most of the benefit of hashing.
If your hacker has a cleartext password and their login ID (email address), you've just given the hacker access to a bunch of their other accounts on non-compromised sites (for the significant % of your userbase that recycles passwords). I think the possible collateral damage creates a far more severe worst-case scenario.
Security is always a battle of usability and tradeoffs. Client-side hashing simply doesn't make sense for security. It removes the fundamental point of the hash in the first place and introduces an avenue for possibly attacking or manipulating your database.
In fact, there's hardly ever a reason to do client-side security.
No, they really don't need that. C.f. SRP (http://srp.stanford.edu/) and similar protocols, where the end user performs a local calculation and the remote party is able to verify identity without ever knowing the password.
This could be the workflow:
1. User enters email address at site. 2. Site sends an email containing a URL with a 512-bit query parameter (yes, this means that user's ISP—and anyone else with access to the email—could sign in once). This parameter might be HMAC(secret, address), enabling the server to store no state for unverified users. 3. User visits URL, and sees a form for email address and password entry. There are hidden fields for the crypto parameters. 4. The user's browser takes the user's address and password, generates a random salt, and calculates a function of the crypto parameters and the local CSPRNG to get the salt a function of the address, password and crypto parameters to get the password verifier. 5. The user's browser POSTs (address, salt, verifier) to the server
Then whenever the user logs in, the browser and server engage in the SRP exchange.
The server never knows the client's password, ever. Nor is someone who knows the verifier able to forge the password.
The best practise is never to transmit sensitive data in the first place.
If you insist on doing this, you can always invert it and hash it on the client side, and send both hashes. You still have access to it, just on the client's computer (running your own code).
No. If you are going to do something like this, do it properly with something like a zero-knowledge password proof.
As you describe it you are introducing a huge flaw: If your password database leaks, an attacker now has everything they need to log in to user accounts, no password hash attacking required.
They also have authenticators before a lot of other people had them. And please use one if you do. Battle.net accounts are targets.
You don't have to do that, my password has capitals, but after I found out the shift the alphas to only one case I stopped typing the caps.
IIRC, the client encrypts the password using some variant of SRP6 plus some additional magic, but the last time I dabbled in wow emulation was quite some time ago.
EDIT Here's a link to a moderator confirmation: http://eu.battle.net/wow/en/forum/topic/2679778775#3
So I hope they're canonicalizing the password casing instead of storing the hash of both possibilities.
> ie. compare both hash(enteredPassword) and hash(invertCase(enteredPassword)) to the hash in the database and see if either match
Here's an example in bash:
$ echo PasSwoRd | tr 'A-Za-z' 'a-zA-Z'
pASsWOrD
In the database store one variant $ echo PasSwoRd | tr 'A-Za-z' 'a-zA-Z' | sha256sum > db
Then you can test both on input $ echo PasSwoRd | sha256sum > sum1
$ echo PasSwoRd | tr 'A-Za-z' 'a-zA-Z' | sha256sum > sum2
$ diff -q db sum1
Files db and sum1 differ # i.e. LOGIN FAILS
$ diff -q db sum2
$ # i.e. LOGIN SUCCEEDS
The problem with the caps lock behaviour on Macs is harder. You definitely don't want to force to uppercase!The reasoning tends to be along the lines of "prevent spammers getting emails" and "security by obfuscation".
But almost all these websites have a sign up page, and if the email address is already in use they will happily let you know that.
Therefore if a hacker/spammer/bad guy wants to brute force your application for emails - they can just use the 'sign up' page to get the emails instead of the 'forgot password' page.
Your use-cases miss out one type of hacker/spammer/bad guy - the one who is only looking for you, they know your email, they want to profile you specifically.
Over the top/exaggerated example (with many implicit caviats!)...
Mr Smith has Mrs Smiths email - he uses it to try to register with a Dating Website - but hold on, it's already registered!
Now there could be 3 reasons for this...
1. infidelity
2. It pre-dates the relationship
3. A third party trying to cause trouble by signing Mrs Smith up.
I don't believe a company has the right to decide what data they hold on you is visible to the outside world - without expressly asking you.
You could have an extra link in your email which lets you update your existing registration details with the ones you've just entered, but that's not going to significantly extend the amount of time you take to register.
Like I said, contrived, but security-by-obfuscation isn't necessarily the sole motivation (though likely the commonest).
Sadly, it doesn't seem to have achieved enough traction (although I still hope).
As long as that link/id remains secret, the user has a unique account to use with no effort on their part.
I'm still not sure this is a good idea, but it seems to work for nightchamber, where the account doesn't actually have much value, and there is no valuable information an attacker could gain by "compromising" the account.
I'm pretty sure at some point we'll have features which are worth protecting and at that time we'll need to offer an opt-in stronger method of account security.
EDIT: for some reason I can't reply to FreezerburnV's comment below, so I'll answer here: yes, I would be interested in talking further about this, drop me an email (in my profile)
I would understand completely if you don't want a random stranger on HN touching/seeing your code though :)
I also am not sure it is a good idea, but one of the by products of this design choice is I had to think harder about what markets I target (I am ruled out of any where the data needs to be protected), how to detect and protect the data of the users in the face of vandals and how to allow for recovery of the data if the vandal countermeasures fail.
While doing this I realized that I should have been dealing with these things anyway and that I was lying to myself about the security of my systems anyway.
I also realized that the login-less user experience is so valuable that until I can replicate it in a truly secure fashion (via client side certificates or something?), I would rather give up on any feature that requires logins.
Also, there are other factors - fonts, monitor dpi, and other factors may make it more difficult to discern between "login" and "log in" on a button, for instance.
8 characters is way too much for someone just 'poking around'. Sure, 6 characters is much less secure, but then again how secure do you need to be for a forum/commenting platform?
It's much better to let the user know his password is weak while letting him take it anyway.
"Sorry, but your password must contain an uppercase letter, a number, a haiku, a gang sign, a hieroglyph, and the blood of a virgin." (old joke)
But why? Your website is not important, do you know?
And if your website is that important (maybe it involves paid subscriptions or something). Then freakin' remind me of those restrictions when I'm trying to log in, so I don't have to think about all the character combinations I might have tried when signing up for your website.
The "not so weak but still crackable" intermediate level doesn't make sense. It's probably going to be reused (how many different 6-character random passwords are you going to remember), so it's just as easy to make it 8 or 12 characters to make it harder to crack when one of the sites inevitably has their password database stolen. If they're not hashing, of course, you're screwed no matter how long the password is.
If you're going to allow 6 character passwords, that indicates there's basically no cost to user account compromise, so why should there be any password testing at all? If a user wants to use the password "1" and gets hacked, that's their problem, they can create a new account after all. It also indicates that user's contributions to the site are probably of low value, since they don't expect to gain any social capital from their contributions that are worth protecting with a better password. If they think the post(s) have value but are going to abandon the account, they can just as easily use "1password" as their password instead of "123123".
It seems like an 8 character minimum and checking against a wordlist is a small price to pay for preventing naive internet users (there are a lot of them) from using horrible, not just bad, passwords.
No I don't.
And "just" a commenting platform doesn't quite cut it for me, people can take their online reputations very seriously. How would it affect the HN community on a whole if tpatec or michaelochurch (insert your own respected user here) were hacked and their profiles destroyed?
At the other extreme, my father commenting on the news couldn't care less if his account is hacked. All he wants is a fast and easy way (using the same password he always uses) to post on the Internet, with a relatively secure way to identify himself to other users on the site.
You need to sit next to someone who doesn't live on the Internet to realize how simple measure, such are requiring a minimum password, can really piss them off.
"Oh, my account got hacked... I guess I'll make another."
"God FUCKING DAMNIT this stupid website won't accept my password!"
I'll grant that there's likely some stuff that some sites want to do on first visit, and that if some do it, users will eventually expect all to be like it. And perhaps that's why we have two dialogs now. But is there any security/pain point related to it? (Assume there's some small snippet of text that makes it clear what's going on, I guess.)
Am I missing something here? 1. I navigate to discourse 2. Select "try discourse" 3. "Sign Up"[0] 4. Dummy username/email 5. Password: 12345678 6. Wait, it succeeded? What did I just read?
Have they not implemented this yet? Maybe I'm the first person to test it? Definitely a common password[1]
[0] http://try.discourse.org/ [1] http://www.cbsnews.com/news/the-25-most-common-passwords-of-...
That bit confuses me - why the need to check the hash? You have the password plain and you have the list plain, just compare the strings directly.
If you have a hashed version of the list and are comparing hashed passwords to that, then you are hashing your passwords wrong: the parameters to your salt function should vary per-password so that people using the same password as each other (or someone using the same password for many accounts) are not obvious should your credentials store be compromised.
If you're just checking to see if it's a common password, wouldn't it be easier to just store a dictionary?
I like this. Captchas annoy the end-user and have been completely broken by foreign manual typers with an API (e.g. http://humancoder.com/). It seems to me pauses would solve the issue, at least an IP level, without any inconvenience to the end-user.
In the best case, implementing this feature lets a user know which of their e-mail addresses are registered on your site, giving them an easier log-in. In the worst case, an attacker can immediately identify what users have accounts on this site, exposing the users to a violation of privacy.
Some counter that site registration will always provide this information when attempting to register an existing e-mail address. But this is easily mitigated: a captcha as well as holding off verification until the last step of registration puts the brakes on the attacker, making it more difficult to scan through potential accounts. By slowing down their attack methods you're helping to reduce risk.
And finally, do we really need to tell the user what e-mail they used? I'll wager that the great majority of users enable browser form-filling, and so their e-mail is sitting right there in the login box waiting for a password. And i'd also wager that most users with multiple e-mails will be cognizant of which they use for an account on a site like yours. So to avoid the few times a user doesn't save form fields and can't remember which e-mail they use for sites like yours, bad people get an easier way to do bad things.
For these reasons I think it's clear that the minor inconvenience in a very small number of cases is worth it to help slow down privacy violation en-masse.
---
Nit-pick: why would God call the field 'User' if they really meant 'Email'?
...
> when presented with a login dialog, like to rapidly type
> [email protected], tab, p4$$w0rd, enter
...
So... Tell me. Considering that you don't block people finding out email addresses on Discourse in the interests of user-friendliness, why on earth are you blocking email addresses, and ones for the purpose of examples at that? An interesting juxtaposition there, and rather ironic, to put it mildly.
Also:
> I think a nice middle ground is to insert standard pauses of moderately increasing size after repeated sequential failures or repeated sequential forgot password requests from the same IP address. So that's what we do.
So what about NATs? There are countries with one public IP address.
What do people use as their outside source for authentication?
Now, I have new 'identities', too - facebook, twitter, linkedin, my phone, etc.
To me, it's a mess, but maybe I'm in the minority.
If you go to tumblr.com it displays the registration page with email/password/username. If you just type in email+password on this page, it still works. So an incomplete registration form can be used to login.
At least my email has a spam filter.
Until then, this post gives advice worth heeding.
>that users could accept an URL as their "identity"
Does this imply Jeff Atwood pronounces URL as earl?
This explains a lot about the quality of his code.