[0] https://onlineunicodetools.com/spoof-unicode-text?input=Noth...
More likely: It's not cargo-cult cultural heritage and stuff is still that bad in some places.
As for hashing bruteforce attacks: no problem, do an initial hashing round on the client before even sending it to the backend.
I'm not sure that would be an actual reason why some designers have decided to limit the set of allowed characters, and your guesses may be better. But it could be something to consider.
https://apple.stackexchange.com/questions/202143/i-included-...
Hash once (on the server) and treat passwords as a binary blob (in other words no validation) until they are hashed. Have some sensible upper bound on how big the password blob can be, but make it larger than any reasonable password manager would create (like 100kb).
I'm not sure what your reasoning is for sending salt to the client should be useless.
Are you arguing somehow that the salt must be private (wrong) and is compromises security in the client ? Think about that for a second, if the client has their traffic sniffed and decrypted, then sending the plaintext password back to the server (your suggested solution) is just as broken.
Client side hashing+salting is a compliment to server-side hasing+salting, not a replacement.
Simplified: The server stores salt and saltedHashFromPassword ( hash(salt+pass) ) On login request server generates salt' and sends salt and salt'.
client sends back hash(salt' + hash(salt+passw)) server compares hash from client to hash(salt' + saltedHashFromPassword)
Now, unless you've owned the client, you'll only ever learn their salt, which is not important, and their salt' which changes with each login request.. the resulting hash cannot be played back as the salt' is invalidated after a login attempt. Assuming a secure hashing algorithm, this even works over plaintext connections.
As to the 64 chars, true, if you're doing no keystreching (which can be plopped over the example above with no problem), however, I assume you're talking about situations where nobody stole the database (the security implications of clinet side hashing are not relevant in that case), but you mean to "just generate that number between 0 and 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff and send that directly to the server".. Well, nope, because you cannot just do 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff requests as the valid hash changes with each attempt to login, I can't even the maths here, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff rasied to the 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffth power attempts might still not get you in, the target is moving and there's no guarantee that you will ever hit it.
However, for passwords, you should allow any sequence of bytes (as much as the system can support it, which it should allow any sequence since they should be hashed anyways), and the maximum length should be sufficiently long (and don't truncate passwords either).
Sometimes it’s just being able to be standards compliant in future:
POSIX stipulates that a dot should separate the user with the group (so jan.harasym is technically an illegal unix user name, and as such might break non-gnu `chown`)
If your username is for a comprehensive suite like Google’s gsuite then having an “@“ or “%” would make your email address invalid.
There could be encoding issues too, but I think the majority of new systems use UTF-8.
I haven’t seen a _real_ encoding issue in about 4 years.
For passwords it's just bad practice. Allow everything, and allow it to be very long.