I need to make an authentication system for an express app I'm building. The client asked to have a password system that uses just a 4-digit pin. I have the code setup to save and hash the pin with the rest of the user info when creating a new user and the project is just an in-house server so it doesn't need to handle a ton of users.
My problem is signing the user back in. I'm using bycrypt to hash the password, but bycrypt generates a completely new hash for identical strings.
What I'm having trouble doing is fetching the user by doing a WHERE hash=hash SQL search. But that's not working because the hash is different every time even when the passwords are identical.
I could get all the users and iterate over all of them and use bycrypt's .compare method. But that won't work in the long run as the amount of users grows, and bycrypt is build to take a long time on cpu's to help prevent brute-force attacks.
I could also build my own hashing function. However, that would make it so I have to store a salt with each user to make each password unique. Then that brings up the same problem of not having the same hash for identical strings.
I know this is vague but I need some help thinking up a way to get the user by fetching it using the hashed password.
Just store the PIN as plain text. Using a hashing function on a 4 digit PIN does nothing but provide a false sense of security. Even an intentionally slow hashing function is easy to brute force if there are only 10,000 possible inputs.
What I'm having trouble doing is fetching the user by doing a WHERE hash=hash SQL search
Are you saying that you don't even know who the person claims to be, but are using the 4 digit pin as both the claim and the proof? It sounds like you building a system with only a pretense of security.
Related
I am creating a web app on a LAMP stack where I have users with their own logins and passwords. Typical users of the application have limits on operations. For example they cannot approve an order over $5000. If there is an order over $5000, they have to get a manager to come to their desk and enter in his/her username and password to approve the order.
I can easily create a form for the manager to enter his/her credentials into an HTML password input, but here is the problem. When the manager enters their credentials into the browser, the password field is hidden from the user. But when the form is submitted, the password is transmitted in clear text. In theory, a user could get the password by using F12 or by looking at the POST.
I wanted to hash the passwords before submitting the form, but the problem is that PHP stores the passwords using BCRYPT, and javascript can only digest with SHA.
So basically my question is. How can I ensure that the manager password is hidden from the user and they cannot get it?
javascript can only digest with SHA
I'm sure you could find implementations of bcrypt in client-side Javascript…
That won't really solve your problem though. If the password is hashed client-side, then the server cannot hash it further and needs to accept the hash as is to compare it directly to the stored hash. Which in essence means, the hash becomes the password, so the user could send the same hash again to the server and pass the test.
Further, bcrypt should be using random salts, so in order to recreate the same hash, the server would need to send the used salt to the client so it can create the correct hash. This is all madness.
Instead, you probably want some sort of challenge protocol. The idea being that the value the client sends to the server is different every time, so even if the attacker sees the value, they cannot reuse it. For this purpose the server would make up some random value, send that to the client, the client calculates some answer given the password and the random value, and sends only that to the server. A rough overview of different algorithm can be found at MDN and elsewhere.
This still won't solve the issue of the attacker installing some keyboard logger, or simply overriding some Javascript handler to log the entered password to the console before answering the challenge. In the end, if you don't trust the attacker and the attacker has full control over the system the password is entered into, there's nothing much you can do.
I use a secure one way hash to store passwords on the server. Can I send this same hash to the client to use as a token.
It is supposed to be an unbreakable one way hash (SHA-256 or similar), plus there is noway to tell that it came from the user password or to even know it is there unless you poke around.
Looking for verification if this is O.K. ?
If it's truly one way then I assume your server validates logins using the hash and not the plaintext. Therefore, sending the password hash is effectively the same as sending the key to the inner door of your home. There's still an outer door but why send more than you need/risk it.
You should strongly consider OpenID Connect for securing applications.
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows
OpenID Connect promotes time-bound authorization codes for web applications. If you're curious why all the indirection and layers, this SO answer is valuable:
What is the difference between the 2 workflows? When to use Authorization Code flow?
In summary, no this is a bad idea.
No. The severity of the issue depends on other details of your system, but in any case it is a bad idea.
If it is a salted hash, properly implemented (salt before hashing, unique random salt per user), then the hash alone will not expose the password. However, passwords are rarely changed, so the hash of the password would rarely change, so anyone who intercepted this hash would be able to use it to impersonate the user for an indefinitely long period of time.
If this hash is not salted, the problem gets a lot worse. A bad actor who intercepts such a hash would have a significant chance of being able to crack the actual password from it. It doesn't matter how technically irreversible the hashing algorithm is, there are huge databases of common passwords and their hashes and for a lot of users cracking an unsalted hash is a simple matter of a database lookup. If the user happens to use this password on many sites, as is common, this could turn into full blown identity theft.
The one part of your idea that is ok is using a token for authentication. That token should be purely random and strictly time-limited, however, with a new one generated each time a user logs in.
This is a no no for various reasons as pointed out by Douglas. Also should your users discover this you would greatly lose their trust in you and your product, and might hurt you legally which I'm pretty sure is not a desirable :).
I would recommend generating a separate token, that probably expires over time, and sending them this instead.
Plus it's fairly simple to implement, therefore no harm in being cautious.
I want to implement an authentication system by following good practices, i want it as simple as possible and secured (im not going to implement some magic hashing function or something to feel a hero..) just wanting to use already known hash but not sure the right way of using it.
I read some articles on how Lastpass (a password management company) mange to handle their authentication and i loved their idea.So i wanted to implement my own authentication based on it.
Basically im creating an authentication key from the password on the client side (so the password is never sent as a plan text to the server).
that authentication key im sending to the server than do some hashing operations also in the server side and compare the result to the one inside the database.
On my client side:
auth_key = PBKDF2(SHA256, password+username, last_login_fe_salt, fe_rounds)
explanation - hashing password+username+last_login_fe_salt text fe_rounds times
last_login_fe_salt -> a random salt sent to the user once he/she input their username in text field -
To be honest, not sure how this last_login_fe_salt is efficent for the cryptography against Dictionary attacks but atleast two people having the same password will send different hashes on their network.
any hacker can get this data by asking from the server, i can add server side limitations (req/s if it makes some difference etc.. let me know what you think) also adding captcha might be a good idea. When a user logged in successfuly the server generates a new random string and saves in into the database.
*I didnt see any explanation which salt Lastpass uses on their client side hashing, they are using PBKDF2 algorithm that needs a salt parameter.
fe_rounds -> number of rounds given by the server when typing username -
its fixed for everybody and configurable by the server, also in articles i read about Lastpass they dont explain from where they receive the client side number of rounds...
so now we send auth_key as is to the server...
On my server side
now we are creating a new hash to compare the one inside the db.
Why another hash? if i understand correctly we bind the hash for server side data, like a combination of a password (that only the user knows) and server data.
db_auth=PBKDF2(SHA256, auth_key, user_be_salt, 100,000+user_configurable_rounds)
user_be_salt -> a random number that saved in db known only to the server and the ones who obtain the database, this changes on every successful login.
user_configurable_rounds -> number of iterations, every user can choose the amount of iterations (like in Lastpass) so attacker need also to guess the number or iterations?
I would be happy to hear what do you think about this authentication system, if its wrong than explain to me why and tell me what Lastpass do because i did not understand their entire authentication flow.
Most of what you're doing is useless from a security perspective. Lastpass has unusual security requirements -- don't treat them as a source of best practices.
If the client is responsible for hashing, and all of the parameters to that hashing are fixed, the hash effectively becomes the password. An attacker doesn't need to know the original password; they can simply pass the hash to the server.
Generally speaking, there is no way to verify a password over a network without either sending the password across the network (for traditional password authentication protocols), or having the server store the password in plaintext (for less commonly used protocols like SRP). Of the two, the former is preferable, as it's possible to secure the password in transit using protocols like SSL/TLS, whereas protocols like SRP require the plaintext of the password to operate.
Tweaking the PBKDF round count, either on the client or server side, is pointless. Set a fixed round count that makes the hash slow, but not so slow that it will place an undue load on the client or server. (100,000 rounds is probably excessive for a server-side hash. It takes roughly half a second to verify a password with those settings, so just two login requests per second would use 100% of one core on your server!)
I'm building a web app that needs to work offline. The system is built to capture sales transactions. The bulk of the "offline" part is fairly straightforward -- I just need to store data locally and sync it when I'm back on the network. So far, so good.
The problem is with authentication. The app will run on a shared machine with a single OS user account. If I'm offline, how do I authenticate the user?
Users themselves do not have any private data that I will need to segregate (i.e., I don't have to protect them from each other on the client). I need to be able to validate their password so I can let different users login throughout the day even if the connection is down.
One approach I'm thinking of involves caching the password hashes on the client-side in an IndexedDB. Only a limited set of users will be allowed to log in from a specific shared machine, so I won't need to cache my whole password database locally. Assuming that I have a good password policy (complexity and expiry requirements) in place and the hashes themselves are secure (bcrypt), just how horrible of an idea is this?
Do I have any other options?
This is effectively how Windows (and other systems) work when the machine is not able to reach the domain controller (e.g., you take your work laptop onto the airplane and need to log into your laptop w/o connectivity). Your machine has written down a cache of your username|password pair and will let you in via those credentials even if it's offline.
I think generally speaking storing the username|password hashes is pretty safe, assuming you're hashing them reasonably (e.g., using a salt, using an IV, etc). One exposure you'll want to think through is having the hash file "escape." If this is sensitive data you'll want to be exceedingly careful -- and this may not even be acceptable, but if it's not super sensitive data then you're probably OK: with good hashing I think you should be reasonably (but certainly not completely) safe.
Maybe this is little unrelated, but I use this approach in my nodejs project.
When a user is authenticated by username and password, he/she is assigned a unique API key used only for this particular session.
Each user can have only one API key.
This API key is added to any request done to server, to authenticate the user.
When the user logs out, the API key is deleted. Also the API key can be purged on the server, that makes the user authenticate on the server one more time.
I can provide links to nodejs open source programs that use this approach if you interested.
I have a quetion which may be simple/dumb or not :). In other words I have no idea if is fair enough or a completely foolish idea. Just some free thoughts.
What if I make my login via JavaScript with pass in it (yes I know), but pass will be hased by Secure Hash Algorithm. For instance:
I generate a pass with SHA which looks like
var = 0xc1059ed8... //etc
and paste into the code. There will be also two functions. One will compare two values (given by me with user's) and second will generate sha form user's input.
Is this could be safe theoritically or this is a horrible pattern and stupid idea? Can JS handle it?
EDIT: I didn't mean serious autentication like banking one. Just when I have my pics and want only to a few ppl to watch them and 99,9% of ppl on earth can't watch them :)
thx for responses
Sorry, no dice :) Secure authentication is not possible with client-side Javascript alone, because a positive authentication result could be faked. You will always need a server-side instance to authenticate against.
The common answer is that 'no, you can't do client side authentication' and for conventional scenarios that is correct, but I can think of at least two ways to make it work:
Use the SHA password hash to redirect to a static HTML page (0xc1059ed8...html). As long as the virtual directory doesn't allow file listing, no one will be able to guess the name of the file you want to protect. This gets clumsy really fast though.
Use an implementation of an encryption algorithm (AES, etc) in Javascript to decrypt a block of text that makes up the actual content of your page. Really only practical for one highly valuable page though.
Server side authentication is really the best, but it is incorrect to say that client side can't be done.
You cannot secure your site with Javascript alone. You will need some way to authenticate requests on the server.
Because all your javascript code is plainly visible to all consumers of your site. All a potential attacker would need to do is view souce of your website and they can bypass the password checking bit of your javascript and view the content behind it.
You need to have security implemented on the server-side, period the end. ASP.NET has a built-in way to do this called "Forms Authentication." Or you could use Session variables in a php script.
Your JS source will be visible anyway and anyone can fake it easily. You have to do a server side validation
Since the hash will reside on the user's computer (in the browser), i'd say it's a terrible idea. It will be easy to manipulate it.
You can use such a pattern to hide the password over a plaintext link and avoid https to login , but not as it stands.
The problem is that an attacker can steal the hashed password and use that to login to the server, and she does not need the real password.
This can be thwarted by a challenge response where the server sends with the page a "salt" : a big random number which is jumbled up with the password and then hashed, so the response is always different.
Unfortunately this has the effect that the server now needs to have plaintext passwords, which is a bad idea (ok, there are some tricks around this). So you might have to end up with a sending a salt, hashing your password, jumbling the hash with the salt by hashing it again and sending that to the server. The server hashes the stored hash of the password from the user db with the salt and compares both.
With security things get complicated real quickly and in complicated things opportunities lurk for the bad guys. A reason more to use well tested patterns, algorithms with a proven track record and libraries which have carefully implemented these.
And in any case it will be the server hwo has final say who can get access.
You'd be better off with no attempt at authentication at all -- at least that way you wouldn't give anybody the dangerous illusion that something involved might be secure.
Assuming you're dealing with a shared-secret situation, authentication is really pretty easy. You use a fairly simple challenge-response algorithm. Basically, the client sends a message to the server saying it wants to log in. The server responds by sending back a random number. The client encrypts that random number with the correct password, and sends it back. The server encrypts the random number itself, and compares the result to what the client sent. If they match, authentication has succeeded -- you've confirmed that the client has the right password.
The advantages of this: first, the password itself is never sent over the wire in any form, so an attacker has virtually no material to use in attempting to discover the password. Second, since the server generates a new random number for every login, an attacker cannot successfully authenticate by re-sending the packets it captured from a previous login.
Nearly any server with any sort of aspirations to security will already have something like this built in. It's purely a question of setting up your client to interact correctly with the form supported by the server(s) you care about.