I can understand that imposing a minimum length on passwords makes a lot of sense (to save users from themselves), but my bank has a requirement that passwords are between 6 and 8 characters long, and I started wondering...
Wouldn't this just make it easier for brute force attacks? (Bad)
Does this imply that my password is being stored unencrypted? (Bad)
If someone with (hopefully) some good IT security professionals working for them are imposing a max password length, should I think about doing similar? What are the pros/cons of this?
Passwords are hashed to 32, 40, 128, whatever length. The only reason for a minimum length is to prevent easy to guess passwords. There is no purpose for a maximum length.
The obligatory XKCD explaining why you're doing your user a disservice if you impose a max length:
A maximum length specified on a password field should be read as a SECURITY WARNING. Any sensible, security conscious user must assume the worst and expect that this site is storing your password literally (i.e. not hashed, as explained by epochwolf).
In that that is the case:
Avoid using this site like the plague if possible. They obviously know nothing about security.
If you truly must use the site, make sure your password is unique - unlike any password you use elsewhere.
If you are developing a site that accepts passwords, do not put a silly password limit, unless you want to get tarred with the same brush.
[Internally, of course your code may treat only the first 256/1024/2k/4k/(whatever) bytes as "significant", in order to avoid crunching on mammoth passwords.]
Allowing for completely unbounded password length has one major drawback if you accept the password from untrusted sources.
The sender could try to give you such a long password that it results in a denial of service for other people. For example, if the password is 1GB of data and you spend all your time accept it until you run out of memory. Now suppose this person sends you this password as many times as you are willing to accept. If you're not careful about the other parameters involved this could lead to a DoS attack.
Setting the upper bound to something like 256 chars seems overly generous by today's standards.
First, do not assume that banks have good IT security professionals working for them. Plenty don't.
That said, maximum password length is worthless. It often requires users to create a new password (arguments about the value of using different passwords on every site aside for the moment), which increases the likelihood they will just write them down. It also greatly increases the susceptibility to attack, by any vector from brute force to social engineering.
Setting maximum password length less than 128 characters is now discouraged by OWASP Authentication Cheat Sheet
https://www.owasp.org/index.php/Authentication_Cheat_Sheet
Citing the whole paragraph:
Longer passwords provide a greater combination of characters and consequently make it more difficult for an attacker to guess.
Minimum length of the passwords should be enforced by the application.
Passwords shorter than 10 characters are considered to be weak ([1]).
While minimum length enforcement may cause problems with memorizing passwords among some users, applications should encourage them to set passphrases (sentences or combination of words) that can be much longer than typical passwords and yet much easier to remember.
Maximum password length should not be set too low, as it will prevent users from creating passphrases. Typical maximum length is 128 characters.
Passphrases shorter than 20 characters are usually considered weak if they only consist of lower case Latin characters. Every character counts!!
Make sure that every character the user types in is actually included in the password. We've seen systems that truncate the password at a length shorter than what the user provided (e.g., truncated at 15 characters when they entered 20).
This is usually handled by setting the length of ALL password input fields to be exactly the same length as the maximum length password. This is particularly important if your max password length is short, like 20-30 characters.
One reason I can imagine for enforcing a maximum password length is if the frontend must interface with many legacy system backends, one of which itself enforces a maximum password length.
Another thinking process might be that if a user is forced to go with a short password they're more likely to invent random gibberish than an easily guessed (by their friends/family) catch-phrase or nickname. This approach is of course only effective if the frontend enforces mixing numbers/letters and rejects passwords which have any dictionary words, including words written in l33t-speak.
One potentially valid reason to impose some maximum password length is that the process of hashing it (due to the use of a slow hashing function such as bcrypt) takes up too much time; something that could be abused in order to execute a DOS attack against the server.
Then again, servers should be configured to automatically drop request handlers that take too long. So I doubt this would be much of a problem.
I think you're very right on both bullet points. If they're storing the passwords hashed, as they should, then password length doesn't affect their DB schema whatsoever. Having an open-ended password length throws in one more variable that a brute-force attacker has to account for.
It's hard to see any excuse for limiting password length, besides bad design.
The only benefit I can see to a maximum password length would be to eliminate the risk of a buffer overflow attack caused by an overly long password, but there are much better ways to handle that situation.
Ignore the people saying not to validate long passwords. Owasp literally says that 128 chars should be enough. Just to give enough breath space you can give a bit more say 300, 250, 500 if you feel like it.
https://www.owasp.org/index.php/Authentication_Cheat_Sheet#Password_Length
Password Length Longer passwords provide a greater combination of
characters and consequently make it more difficult for an attacker to
guess.
...
Maximum password length should not be set too low, as it will prevent
users from creating passphrases. Typical maximum length is 128
characters. Passphrases shorter than 20 characters are usually
considered weak if they only consist of lower case Latin characters.
My bank does this too. It used to allow any password, and I had a 20 character one. One day I changed it, and lo and behold it gave me a maximum of 8, and had cut out non-alphanumeric characters which were in my old password. Didn't make any sense to me.
All the back-end systems at the bank worked before when I was using my 20 char password with non alpha-numerics, so legacy support can't have been the reason. And even if it was, they should still allow you to have arbitrary passwords, and then make a hash that fits the requirements of the legacy systems. Better still, they should fix the legacy systems.
A smart card solution would not go well with me. I already have too many cards as it is... I don't need another gimmick.
If you accept an arbitrary sized password then one assumes that it is getting truncated to a curtain length for performance reasons before it is hashed. The issue with truncation is that as your server performance increases over time you can't easily increase the length before truncation as its hash would clearly be different. Of course you could have a transition period where both lengths are hashed and checked but this uses more resources.
Try not to impose any limitation unless necessary. Be warned: it might and will be necessary in a lot of different cases. Dealing with legacy systems is one of these reasons. Make sure you test the case of very long passwords well (can your system deal with 10MB long passwords?). You can run into Denial of Service (DoS) problems because the Key Defivation Functions (KDF) you will be using (usually PBKDF2, bcrypt, scrypt) will take to much time and resources. Real life example: http://arstechnica.com/security/2013/09/long-passwords-are-good-but-too-much-length-can-be-bad-for-security/
In .net core 6 I use HashPasswordV3 method that it use HMACSHA512 with 1000 iterations. I tested some password length and it generate a 86 characters hash.
So I set the PasswordHash field in sql server for varchar(100).
https://stackoverflow.com/a/72429730/9875486
Storage is cheap, why limit the password length. Even if you're encrypting the password as opposed to just hashing it a 64 character string isn't going to take much more than a 6 character string to encrypt.
Chances are the bank system is overlaying an older system so they were only able to allow a certain amount of space for the password.
Should there be a maximum length? This is a curious topic in IT in that, longer passwords are typically harder to remember, and therefore more likely to get written down (a BIG no-no for obvious reasons). Longer passwords also tend to get forgotten more, which while not necessarily a security risk, can lead to administrative hassles, lost productivity, etc. Admins who believe that these issues are pressing are likely to impose maximum lengths on passwords.
I personally believe on this specific issue, to each user their own. If you think you can remember a 40 character password, then all the more power to you!
Having said that though, passwords are fast becoming an outdated mode of security, Smart Cards and certificate authentication prove very difficult to impossible to brute force as you stated is an issue, and only a public key need be stored on the server end with the private key on your card/computer at all times.
Longer passwords, or pass-phrases, are harder to crack simply based on length, and easier to remember than requiring a complex password.
Probably best to go for a fairly long (10+) minimum length, restricting the length useless.
Legacy systems (mentioned already) or interfacing outside vendor's systems might necessitate the 8 character cap. It could also be a misguided attempt to save the users from themselves. Limiting it in that fashion will result in too many pssw0rd1, pssw0rd2, etc. passwords in the system.
One reason passwords may not be hashed is the authentication algorithm used. For example, some digest algorithms require a plaintext version of the password at the server as the authentication mechanism involves both the client and the server performing the same maths on the entered password (which generally won't produce the same output each time as the password is combined with a randomly generated 'nonce', which is shared between the two machines).
Often this can be strengthened as the digest can be part computed in some cases, but not always. A better route is for the password to be stored with reversible encryption - this then means the application sources need to be protected as they'll contain the encryption key.
Digst auth is there to allow authentication over otherwise non-encrypted channels. If using SSL or some other full-channel encryption, then there's no need to use digest auth mechanisms, meaning passwords can be stored hashed instead (as passwords could be sent plaintext over the wire safely (for a given value of safe).
Microsoft publishes security recommendations for developers based on their internal data (you know, from running the biggest software enterprise in the history of computing) and you can find these PDFs online. Microsoft has said that not only is password cracking near the least of their security concerns but that:
“Criminals attempt to victimize our customers in various ways and
we’ve found the vast majority of attacks are through phishing, malware
infected machines, and the reuse of passwords on third-party
sites—none of which are helped by very long passwords." -Microsoft
Microsoft's own practice is that passwords can be no longer than 16 and no shorter than 8 characters.
https://arstechnica.com/information-technology/2013/04/why-your-password-cant-have-symbols-or-be-longer-than-16-characters/#:~:text=Microsoft%20imposes%20a%20length%20limit,no%20shorter%20than%20eight%20characters.
I found using the same characters for the first 72 bytes of a password gives a successful verification using password_hash() and password_verify() in PHP, no matter what random string comes after the first 72 bytes.
From PHP docs: https://www.php.net/manual/en/function.password-hash.php
Caution: Using the PASSWORD_BCRYPT as the algorithm, will result in the password parameter being truncated to a maximum length of 72 bytes.
Recent Updates from OWASP now recommend a max length:
https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
Maximum password length should not be set too low, as it will prevent users from creating passphrases. A common maximum length is 64 characters due to limitations in certain hashing algorithms, as discussed in the Password Storage Cheat Sheet. It is important to set a maximum password length to prevent long password Denial of Service attacks.
Just 8 char long passwords sound simply wrong. If there ought to be a limit, then atleast 20 char is better idea.
I think the only limit that should be applied is like a 2000 letter limit, or something else insainly high, but only to limit the database size if that is an issue
Related
So Bcrypt does have a limit for how long passwords can be. I have read many pages regarding this. The one thing I can't figure out is how most sites bypass this.
Most sites I have noticed don't have a max password length. Maybe I'm totally wrong about this but that is just what I have noticed. Bcrypt seems to be one of the most popular libraries for this type of thing.
So are all of these sites just not alerting users and Bcrypt is cutting the passwords to the max character limit and not alerting users? Or are they doing some special technique to allow for longer passwords?
I'm just trying to figure out how to best implement this. I would love to have no max character limit. But at the same time I want to be straight forward with users and if Bcrypt is cutting passwords users should know about that.
Any suggestions for how to handle this limitation in practice?
Even if the question is already answered, I would like to point out two things:
The length of passwords the user can enter should not be limited, that's correct. BCrypt has no problems to work with passwords longer then 72 characters though, it will just truncate the password to this length. So accept passwords of any length, pass them directly to BCrypt or use the scheme from Zaphs answer.
Hashing 72 character passwords is more than enough to be on the very safe side. Even 20 character passwords cannot realistically be brute-forced.
A 72 character password would allow for 1E129 combinations (without special characters). Very fast hashes can be calculated with 100Giga/second. Even in this worst case you would need about 1E110 years to expect a match, that is about 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 times the age of the universe!
Be aware when combining different hash algorithms:
If done correctly this can increase entropy, if the entered password is longer than 72 characters (which is rarely the case) and if the password is not random like (which is unlikely if somebody takes care to use such long passwords). A lot of ifs.
And there are pitfalls:
If you use the binary output of the SHA-512 then you could stumble over \0 characters, which can lead to unsecure hashes, see this article.
If you use the hex/base64 representation of the SHA, you limit the possible characters for the 72 places.
I see no problem with first running SHA-512.
According to the NIST SP 800-63-3 Draft document "Digital Authentication Guidelines" passwords SHALL accept (and use) at least 64 characters, if they accept more it must not be truncated.
In reality NIST is recommending use of PBKDF with any of SHA-1, SHA-2 family, SHA-3 family, even with SHA1 there will essentially be no collision and even if there is it is not a problem for password hashing. The key is the iteration count to slow down the attacker.
Read the answer comment by #ilkkachu in the links answer.
Note: This doesn't explicitly relate to programming, but I was hoping this can be explained from a programmers point of view.
There are two things I simply don't understand about current 'password strength ratings'. This all pertains to brute force entry. (If these 'password strength ratings' relate to any other type of breach aside from using a common/popular password please let me know).
1) Why does it matter if I include numbers/symbols/uppercase letters as long as the password system allows for the possibility of using them?
For example lets just say:
a) The systems accepted characters are a-z, A-Z, 0-9, and their "shifted values" '!' to ')', so 72 possible symbols.
b) I use a password of length ten, so 72^10 possibilities.
c) My password is not in the top 10,000 most common/popular passwords used. So 72^10 - 10,000 possibilties remain.
Wouldn't an all lowercase password like 'sndkehtlyo' be identical strength as 'kJd$56H3di' since they both share the same possibility of including the additional characters? Doesn't the brute force algorithm have to include those numbers/symbols/uppercase regardless of whether or not I use them? It seems like these rating systems believe a brute force attempt will try all 26^n lowercase passwords first, all 52^n passwords second, then all 62^n passwords, etc, etc.
2) Why does that even matter? I have yet to come across any password system that doesn't lock you out after some small fixed number of attempts (usually 5). How can brute force approaches even work these days?
I feel like I am missing something fundemental here.
1) Cracking a password doesn't need to happen in one pass. A well implemented brute force crack may iterate first through small ranges of characters and then work its way into caps and numbers. Starting with the simplest ranges first (maybe just lowercase a-z) will find passwords of those unfortunate enough to have constructed a weak password. They may also start with dictionary attacks or Most-common-passwords-used attacks first as they take very little time.
2) Crackers aren't going to brute force right through some online service's login prompt. Anyone truly intent on getting access to an account would retrieve the hash of a user's password and crack it on their own machine, not over the internet. While there are practically infinite ways to hash a password there are some very common methods that can be identified by properties such as the hash's character length. You can read more about common hash algorithms in this Wikipedia article.
1) All man-made passwords are not totally random. In other words, taking the human factor (e.g. memorability), the probability distribution of a password space is not even.
2) The attempt times restriction is used for authentication, which is a means of Access Control. It has nothing to do with the password strength. It is the system level control method and it is usually configurable. Of course, it is an effective weapon against brute force attacks, but one can still design a system without that access control method. Also, hackers may not crack into the system directly but they could intercept the user data from the network which contains encrypted password or anything else and use brute force or other ways to crack it. So a high-strength password scheme, a high-security crypto method and a well-designed access system could live together to make a strong security system.
In general, with a brute force system, you are correct. But, a lot of automated password crackers out there begin their searches by trying common english words and their combinations. For example: sports teams, states, dates, etc etc... So by having those special characters it immediately eliminates a lot of those possibilities. Generally, if you're worried about brute force, a much longer password is more secure than a shorter one with special characters.
When storing passwords, it's been said that Salt doesn't need to be secret and it's only purpose is to keep all Hash unique. It's also said that limiting password length is not a good practice but consider this example:
Before hashing, we make sure the plain text version is always 128 characters internally by trimming user input to max 100 then appending additional characters as our salt.
So if user inputs 20 characters, we append 108 random characters as salt. If user inputs 100, we append 28, and so on. The point is, the length of the plain text version should be 128 characters. In code it might look like this:
$salt = generate_salt($pass); // length varies as explained above
$hash = hash('sha512', $pass.$salt);
This way our "plain text" before hash will always be 128 characters.
We store $hash on Server A and store $salt on Server B.
Now let's assume the attacker gains access to hash DB (Server A) and manages to reverse the hashes. Looks good for him but the plain text version (or the reversed hashes) that he sees still looks like hashes since it's 128 characters. Since he doesn't know the salt he will never know the original password.
As an added challenge, due to the fact that SHA512 produces 128 characters he'll also never be sure if he already arrived at the plain text version since (like already mentioned) the plain text version looks like hashes. On plain sight he might think it's an iterated version, if so he'll probably continue to iterate, possibly indefinitely.
Is there any problem with this approach since in the event of hash reversal, keeping the salt secret gives extra security, and, keeping plain text length uniform arguably adds layer of obfuscation?
Note: This of course assumes your app has multiple failed login detection/prevention.
First of all, unless you really know what your doing, don't invent your own crypto system.
Use an existing one (like PBKDF2, bcrypt or scrypt), which have advantages over simple salted hashes, since they use more CPU time (all three) and/or memory (the latter two), which makes parallelization expensive.
The salt in a hash protects only against rainbow tables, not against brute-force attacks!.
If the attacker manages to reverse the hashes, he will gain knowledge of $pass.$salt (an, therefore, the password).
The purpose of a salt is to avoid an inexpensive creation of rainbow tables, that is, instead of just calculating the hashes of every probable password and comparing them to your database, an attacker has to do this for every different salt.
Keeping the salt secret has the theoretical advantage of making the attack even more expensive, since the attacker would also have to try every possible salt for every possible password.
In practice, however, he will probably be able to gain access to server B once he has access to server A.
If something looks like a hash is probably not important. Once the server is compromised, the attacker could probably find out what obfuscation techniques are used.
On a side note: SHA-512 produces 512 bits of output, which are 64 ASCII characters.
The first problem with this approach is that you're implementing your own cryptographic code. This is almost always a bad idea; crypto is hard, and very easy to screw up in subtle ways, and other people have put a lot of time and effort into implementing cryptographic primitives and services built on top of them so that you don't have to. But let's assume for the sake of argument that you really do need to do this :-).
The second thing is that you're truncating the user's input -- throwing away precious entropy -- for no benefit at all. You're prepared to generate up to 128 characters' worth of salt; why not just always do this and feed them (together with the password) into your hash? What do you gain by truncating? The only answer I see is that supposedly the original passwords "look like hashes since it's 128 characters", but that simply isn't true; your salted passwords still begin with actual password data, which typically looks very much unlike hashes.
The third thing -- which may just be a failure on my part to read your mind correctly -- is that it's not clear where these salts of yours are coming from. You describe them as "random" and say attackers won't know them; but then how does your authentication system get them? It seems like they're derived from the password, but in that case salting-plus-hashing is just a marginally more complicated hash function and you haven't really gained anything.
The general principle you've apparently rejected (or perhaps not encountered) is this: Always design cryptographic systems with the assumption that the attackers know everything they could possibly know, including all your source code. This is a good principle and you should not reject it. Relying on a small "extra layer of obfuscation" will not serve you well; in the worst case it will make bugs more likely (by complicating the system) and induce a sense of false security.
Salt doesn't need to be secret and it's only purpose is to keep all Hash unique
It also makes it 'slower' to brute-force a table of hashes, since you need a try per row for every hash + salt combination instead of just trying out one hash for the whole table (' select * from passwords where hash = 'xxx' ')
keeping the salt secret gives extra security, and, keeping plain text length uniform arguably adds layer of obfuscation?
The fact that your 'reversed hashes' look like hashes does not add real extra security (it's really just security by obscurity). Your webserver will need to connect to server A and server B (for authenticating a user / password combination) so when that server is compromised all hope is lost.
An article that may interest you is this blog post by Jeff Atwood. (edit: posted wrong codinghorror link)
Right now my login system is the following:
Password must be at least 8 characters long, and contain at least one upper and lowercase letter, a number and a symbol.
Password can't contain the username as its substring.
Username, salted+hashed (using SHA2) password stored on db.
The nonce (salt) is unique for each user and stored as plaintext along with the username and password.
The whole login process can only be made over TLS
How would you rank the effectiveness of the following measures to increase security?
Increase password length
Force the user to change the password every X period of time, and the new password can't be any of the last Y previous passwords
Increase nonce size from 32 bytes to 64 bytes (removed for uselessness)
Encrypt the salt using AES, with the key available only to the application doing authentication
Rehash the password multiple times
Use a salt that's a combination of a longer, application-wide salt + unique user salt on the db.
I am not very fond of 1 and 2 because it can inconvenience the user though.
4 and 6 of course are only effective when an attacker has compromised the db (eg: via SQL injection) but not the filesystem where the application is in.
The answers may depend somewhat on the nature of the website, its users and attackers. For instance, is it the kind of site where crackers might target specific accounts (perhaps "admin" accounts) or is it one where they'd just want to get as many accounts as possible? How technical are the users and how motivated are they to keep their own account secure? Without knowing the answers, I'll assume they're not technical and not motivated.
Measures that might make a difference
5) Rehash the password multiple times. This can slow down all brute force attacks significantly - hash 1000 times and brute force attacks become 1000 times slower.
4) Encrypt the salt using AES, with the key available only to the application doing authentication How would you make it available only to the application? It has to be stored somewhere and, chances are, if the app is compromised the attacker can get it. There might be some attacks directly against the DB where this makes a difference, so I wouldn't call this useless, but it's probably not worthwhile. If you do make the effort, you might as well encrypt the password itself and any other sensitive data in the DB.
6) Use a salt that's a combination of a longer, application-wide salt + unique user salt on the db. If you're only concerned about the password then yes, this would be a better way of achieving the same result as 4) and, of course, it's very easy to implement.
Ineffective measures
3) Increase nonce size from 32 bytes to 64 bytes. Computing rainbow tables is already completely impractical with any salt, so this would only make a difference if the salt was not known to the attacker. However, if they can get the hashed password they could also get the salt.
Ineffective and annoying measures
1) Increase password length Increasing password length beyond 8 won't make a practical difference to the brute force time.
2) Force the user to change the password I agree, this will always be worked around. In fact, it may make the site less secure, because people will write down the password somewhere!
Increasing password length add a few bits of entropy to the password.
Requiring frequent password changes will generally force the users to use less secure passwords. They will need to figure out what the password is in May, June, July. Some#05x, Some#06x, Some#07x.
Can't say for sure, but I would expect the password length to be more significant in your case.
Slightly more secure. But if someone gains access to your data, they can likely gain access to the key.
Other than increasing CPU costs, you won't gain anything.
There are a number of well tried one-way password encryption algorithms which are quite secure. I would use one of them rather than inventing my own. Your original items 1, 2, and 5 are all good. I would drop 3, and 4.
You could allow pass phrases to ease password length issues.
I would suggest that you read http://research.microsoft.com/en-us/um/people/cormac/papers/2009/SoLongAndNoThanks.pdf
This paper discusses part of the reason it is hard to get users to follwo good security advice; in short the costs lie with the users and they experience little or no benefit.
Increasing the password length and forcing more complex passwords can reduce seciryt by leading to one or both of; reused passwords between sites/applications and writing down of passwords.
3 Increase nonce size from 32 bytes to 64 bytes
4 Encrypt the salt using AES, with the key available only to the application doing authentication
5 Rehash the password multiple times
These steps only affect situations where the password file (DB columns) are stolen and visible to the attacker. The nonce only defeats pre-hashing (rainbow tables), but that's still a good thing and should be kept.
(Again, under the assumption you're trying to minimize the impact of a compromised DB.) Encrypting the nonce means the attacker has an extra brute-force step, but you didn't say where the encryption key for the nonce is stored. It's probably safe to assume that if the DB is compromised the nonce will be plaintext or trivially decrypted. So, the attacker's effort is once again a brute-force against each hash.
Rehashing just makes a brute-force attack take longer, but possibly not much more so depending on your assumptions about the potential attacker's cracks/second.
Regardless of your password composition requirements a user can still make a "more guessable" password like "P#ssw0rd" that adheres to the rule. So, brute force is likely to succeed for some population of users in any case. (By which I mean to highlight taking steps to prevent disclosure of the passwords.)
The password storage scheme sounds pretty good in terms of defense against disclosure. I would make sure other parts of the auth process are also secure (rate limiting login attempts, password expiration, SQL injection countermeasures, hard-to-predict session tokens, etc.) rather than over-engineering this part.
For existing:
e1: I see where you're coming from, but these rules are pretty harsh - it certainly increases security, but at the expense of user experience. As vulkanino mentions this is going to deter some users (depends on your audience - if this is an intranet application they have no choice... but they'll have a yellow sticky with their password on their monitor - cleaners and office loiterers are going to be your biggest issue).
e2: Is a start, but you should probably check against a list of bad passwords (eg: 'password', 'qwerty', the site URL)... there are several lists on the net to help you with this. Given your e1 conditions such a scan might be moot - but then surely users aren't going to have a username with 8 chars, upper+lower, a symbol and a number?
e3: Good call - prevent rainbow attacks.
e4: Unique salt prevents identification of multiple users with the same password, but there are other ways to make it unique - by using the username as a secondary salt+hash for example.
e5: Solid, although TLS has built in fall-backs, the lower end TLS protocols aren't very secure so you may want to check you're not allowing these connections.
New ideas:
n1+n2: e1 is already painful enough.
n3: No discernible benefit
n4: No discernible benefit - whatever the encryption process is would be available in the code, and so also likely compromised. That is unless your DB and App servers are two different machines hardened for their own tasks - in this case anything you can avoid storing with the password is helpful in the event the DB is compromised (in this case dropping unique salt from the database will help).
n5: Rehashing decreases brute force attack speed through your application - a worth while idea in many ways (within reason - a user won't notice a quarter second login delay, but will notice a 5 second delay... note this is also a moving target as hardware gets better/faster/stronger/work it)
Further points:
Your security is only as good as the systems it is stored on and processed through. Any system that could be compromised, or already has a back door (think: number of users who can access the system - server admins, DBAs, coders, etc) is a weak link.
Attack detection scripts in your application could be beneificial - but you should be aware of Denial of Service (DoS) attacks. Tracking failed logins and source is a good start - but be aware if you lock the account at 5 failures, someone could DoS a known account (including the admin account). Being unable to use the App may be as bad as loosing control of your account. Multi-hash (n5) slows down this process, picking a slower hash algorithm is a good step too, and perhaps building in re-attempt delays will help too (1 second on first fail, 2 on second, etc)- but again; be DoS aware. Two basic things you might want to filter: (1) multi attacks from the same source/IP (slow down, eventually prevent access from that IP - but only temporarily since it could be a legitimate user) perhaps further testing for multiple sets of multi attacks. (2) Multi attacks from different IPs - the first approach only locks a single user/source, but if someone uses a bot-net, or an anonymizing service you'll need to look for another type of suspicious activity.
Is it possible to piggy-back off another system? You could use an LDAP, or Active Directory server in your domain or use OpenID or OAuth or something similar. Save yourself all these headaches by off loading the work ;) {Inter-system security still needs to be addressed if you're a middle man} Plus the less passwords users have to remember (and rules attached to each) the more likely they are to have a good password, that isn't written down, etc.
I don't consider any of those things to increase your password security. The security of the password stored in the database is only relevant if you expect someone to obtain a copy of the database. Using a (perceived) stronger hash function in the database only obfuscates your application. In fact a salted MD5 would be fine (I am aware of the attacks on MD5, and don't believe any of them to be relevant to password hashing).
You might be better relaxing the password rules to get better security, as if you require at least one upper and lower LATIN letters, you effectively force non-latin keyboard users to use alien letters (try typing upper and lower case latin letters on a cyrilic keyboard). This makes them more likely to write it down.
The best security would be to avoid using passwords in their entirety. If it is an enterprise application in a corporate that uses Active Directory, consider delegating authentication instead of writing your own. Other approaches can include using an Information Card by making your application claims-aware.
How about encrypting the password in client browser already with MD5/SHA, then treat the hash as user's password at server side. This way the password isn't in plain text when it travels over SSL/TLS nor it is never-ever in plain text in server either. Thus even it is stolen by hackers at any point (man-in-the-middle, server/db hacks), it cannot be used to gain access to other web services where the user might have same email/username+password combo (yes, its very common...)
It doesn't help with YOUR site login security directly, but it certainly would stop hacked password lists spreading around the net if some server has been hacked. It might work to your advantage as well, if another, hacked site applies the same approach, your site user's aren't compromised.
It also guarantees all users will have decent alphanumeric password with enough length and complexity, you can perhaps then relax your requirements for password strength a little :-)
A hypothetical situation: you've implemented a password handling system, and it doesn't impose any limitations at all on what characters can be used. You want to set up some rules that are a reasonable compromise between two things -
Allow the user as much freedom as possible.
Allow for the possibility that you may change how you handle passwords in the future - you don't want to rule out reasonable implementations because your users' existing passwords would become invalid.
What rules would you impose? Are there other factors that might affect you choice?
Do not impose no restrictions whatsoever, ever. And it seems to me that you're planning on storing password, not hash. Do not do that either. Rather, store salt and hashed combination of password and said salt.
However, you can require your users to have a reasonably strong password by imposing restriction on length (say, not less than 6 characters) and on characters which comprise the password (say, it should contain lower- and uppercase alphabetic characters, one or two digits and several non-alphabetic characters such as ^ or #).
Best is no restrictions whatsoever, unless you can really justify them.
If you are a bank, email provider, or if the user can order something without supplying a credit card, then forcing users to use a strong password makes sense. Otherwise, you're just making it hard for no reason.
As to what you should store, I'd say 1024 characters of unicode with control characters prohibited is about all that's justified. If the user can't type it, they should have picked a different password. All you're storing is a hash, so you can always cut it down to whatever size you want.
No limit on the password. If they can type it from their keyboard, regardless of what regional keyboard they use. You may want to impose a minimum length, options like at least one number and one special character, but no max limit.
Regarding your second question. The way I would implement it is via making seperate fields as you improve password strength. For example, right now you would have two fields that relate to the password: salt, password_md5. Lets say later on you want to use sha256. Create a new field called password_sha256. When the user logs in you first check password_sha256. If that field is empty then check password_md5. If that matches you now have the plain text password the user entered. You can then generate the sha256 password (I'd also reset the salt for good measure) and store the new value. I would then blank out the value in password_md5 so no one could reverse that to get the password.
Personally I'd just go with the best hash your language can do and use that. The important things are enforcing a good minimum password policy--it doesn't matter how secure the hash is when the password is "1234"--and to seed the hash with some random character to avoid dictionary attacks.
Any non-control character should be fine. I should think that the developers of super-duper password systems in the future would allow "unusual" ASCII characters like punctuation and other marks, but control characters have a habit of being unwieldy to enter in text mode shells and even GUI dialogs that expect Tab and Enter/Return to be free for their own purposes.
A blank space (based on the logic it may be trimmed accidentally before being hashed)
Personally I have always been keen on not enforcing too many rules.
This has just changed. I have just found my website is vulnerable to XSS attacks. The solution is to sanitise every piece of input that comes from the user, including the password.
For 10 years we have had no limits on the password.
Now we are implementing a limit to the characters that can be used, and this is simply to block hackers from being able to access Javascript or SQL. So we constructed the following list:
Valid characters for a password are: a-z A-Z 0-9 . - _ $ * ( ) # # ! % / (blank)
This allows lots of flexibility but avoids characters that might be used in coding an XSS hack, such as ; < > \ { } [ ] + = ? & , : ' " `
HTH
In our organization, if the user is supplying the password we allow them to use anything they want.
When users are first enrolled in the system a password is generated for them. Since this password is usually mailed to them, we avoid using certain characters that could be confused particularly when using certain fonts. For example, the letter O and the number 0 (zero) are not used. The same for L, I and 1 (one), S and 5, Z and 2 and others.
Before we made this change we had a lot of calls to our help desk because the characters were confusing and they couldn't log in.
I'd keep anything you can make with one key (and optionally shift) on your keyboard, except tab. What kind of schemes would necessitate a more restrictive option?
Have the users type passwords that contain at least a number and a non-alphanumeric character, and be more than six characters long. Anyway, I think that whatever the limitations, in the event that you change the way you validate passwords, you should notify users in reasonable time to update theirs.
Personally, I use DigitalPersona's Fingerprint Keyboard (yes, Microsoft does [or did] make a similar device, both integrated with or separate from the keyboard).
This allows the generation of extremely long and complicated passwords that don't have to be written down (as the press of your finger on the reader supplies the password to the Logon dialog [system/application/website]).
This, in my opinion, provides the best of both worlds: Extremely difficult to "guess" passwords, without having to remember them. It also makes simple the additional security recommendation of using different passwords on different systems.
Well, that's my two-cents' worth.
Some rules to follow:
Avoid Control Characters. It's not as prevalent today, but control characters all have special meanings and some hardware intercepts control characters to perform special functions. Some will cause data issues Example Control 0 (Zero) would generate a null.
Are you going to impose security restrictions? This is a user interface question as well as a security issue. What is your application and it's need for security. Many of the examples previously given are out of date. Hash tables for combinations of passwords are published for up to 15 character passwords and 16 character passwords can be brute forced withing minutes if the password is otherwise weak or follows typical human behavior. Starts with a capital, ends with number or special character.
I'd avoid common wildcard characters, quotes, colon, semi-colon, etc... that are commonly used in OS or DB languages.
Multi-factor authentication is a good way to go. Don't depend upon the password only or don't accept passwords at all.