**TL;DR:** Just use HTTPS and send the credentials, unhashed, in a POST request. It's much safer, simpler, and takes care of passive monitoring, MITM, and replay attacks all at the same time. --- > Are there any vulnerabilities with this strategy? Several. Let's start with the most straightforward, though: 1. Logging in over plain text is never secure. Even if you somehow manage to fully protect the password, the attacker can just steal the session token returned from your /api/ajax-login request, or otherwise hijack the fully-authenticated session, using passive monitoring. With an active MITM attack, the login page will get a malicious script injected that transmits the user's credentials directly to the attacker, exposing the password anyhow. Use HTTPS; there's no good reason not to. Even unauthenticated HTTPS (HTTPS without a trusted cert) is better than nothing, both because it requires active interception or misdirection to spoof, and because a knowledgeable user could at least achieve trust-on-first-use and note if an attacker later spoofs the server. However, trusted TLS certs are obviously what you should use anywhere you can. 2. Don't use GET requests for authentication. In general, don't put any secret values into URLs, even within HTTPS (and definitely not without it). URLs are often stored in log files, on the web server or on a proxy or even in the browser (even for AJAX, though in fewer places on the browser than top-level navigation). Authentication requests should be POST (or possibly another verb, but POST is the usual) requests, with the secrets (credentials) in the body. 3. Storing passwords hashed without salt is insecure, because it means both that any two users with the same password will have the same password hash, and it's very easy for an attacker to use a rainbow table or GPU to crack approximately all of your passwords in parallel, extremely quickly. Each password needs to be hashed with a unique salt. 4. Hashing the password only on the client is insecure. It makes the stored password hashes in the DB password-equivalent, meaning that the attacker only needs to know the password hash - not the original password at all - to log in as the user. Since the password hashes are what the DB stores, any breach of the DB will expose all your users' credentials. It's almost as bad as not using hashing at all. Instead, you *MUST* hash on the server, using a strong, slow, ideally memory-hard, and salted algorithm suitable for password hashing (I recommend argon2id, though older algorithms such as scrypt, bcrypt, or even PBKDF2 are still better than this). You *can* pre-hash on the client if you want (and then re-hash the client-generated digest, securely, on the server), but for simple login, there's honestly not really a good reason to do so. 5. *EDITED TO ADD* Related to #4: It's not possible, with this scheme, to store non-password-equivalent secrets on the server. You could hash them more thoroughly, make it harder to crack the hashes and figure out the original passwords, but using this scheme there's no way to store, on the server, values that can't be directly used to log in as the various users. There are other things that aren't obviously wrong, but are concerning. * What hash are you using today? As mentioned above, there are many properties of a hash suitable for passwords. If your hash is too fast (and most are), then it's trivial to brute-force it once the salt is known (or if no salt is used, as in the case of your database today). A modern GPU can compute billions of hashes using common hash algorithms *each second*. Your users are probably using one of the billion or so most common passwords, so it's easy to brute-force the password from the hash that way, in potentially less than a second. * How long is your salt? Your replay protection rests on the attacker not being able to choose the salt, but if the salt is short enough, the attacker can just request new salts until they get the one that was used before, and then replay the auth request. * Relatedly, how good is the entropy of your salts? If you're using a standard insecure PRNG, an attacker can observe some number of outputs, and then predict the rest of them forward and backward, meaning the attacker can predict when the one they want will be returned again. * How does your server tie a specific salt to a specific username? Is the username sent before the salt is returned, and the pair stored in the DB or similar on the server? If the client has any say in tying the salt to the username, then an attacker can spoof that. --- One other option to consider: look into the [Secure Remote Password (SRP) protocol](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol), and secure password authentication/key exchange algorithms. There are still some areas that SRP doesn't handle (such as initially setting or rotating passwords) but it's a good example of a secure algorithm that does what you're trying to do.