8

I'm writing a small webapp and I don't want to transmit login passwords as cleartext. As I don't have SSL available I've written a one-time challenge system which sends a random string with the login form which is then used to hash the password using HMAC-SHA256 on the client-side. I use the random challenge string as the message and the user's password as the secret key for HMAC.

I know that self-made solutions are generally a bad idea, so I wanted to ask if I'm making a mistake here.

Edit: There seems to be a misunderstanding, I'm not asking about password storage or challenge/repsonse systems, but about HMAC and password transmission. To clarify a little: My first version was HMAC(msg=password, key=challenge), because I thought, well, the message I want to transmit to the server is the user's password. But later I noticed that the challenge string is not exactly a secret key, so I switched it, but that got me thinking if I maybe do something entirely wrong and I thought I better ask about it.

9
  • I realize this is off-topic to your question, but depending on your user base, you might consider using one-time passwords instead. For example, motp.sourceforge.net will give you one-time passwords and integrates with most smart phones (and normal computers, of course).
    – gowenfawr
    Sep 5, 2011 at 13:43
  • 2
    What threat are you trying to defend against?
    – D.W.
    Sep 5, 2011 at 18:21
  • I want to protect against sniffing of passwords by simply eavesdropping on an insecure connection, I'm not trying to replace SSL.
    – Steffen
    Sep 6, 2011 at 3:50
  • Does the connection go over the internet?
    – this.josh
    Sep 7, 2011 at 1:43
  • 1
    Why is SSL not available is it a legal or policy requirement?
    – this.josh
    Sep 7, 2011 at 7:21

4 Answers 4

11

Besides being a self-invented scheme, I see at least the following problems with your proposal:

  • There is no binding with the actual data. When you authenticate a user, you do not want to really authenticate "the user" only; you want to authenticate a session, i.e. make sure that what will follow on the link will be guaranteed to be from that user, and what you will send on the link will be seen only by the intended user. An active attacker can hijack the connection, and even a passive eavesdropper can spy on whatever you will send afterwards.

  • The scheme is vulnerable to offline dictionary attacks. Passwords are weak because they fit in human brains, and human brains are not overly good at remembering long passwords (and human users lack patience to type long passwords). It is a losing battle: computers regularly gain more power, but not humans. Trying out potential passwords tends to be a successful attack, and observing your scheme yields enough information to try passwords (the attacker just has to compute a single HMAC per guessed password, and see if it matches what was observed). Such attacks can be mitigated to a great extent by employing a slow derivation process (e.g. bcrypt) but a single HMAC will just not be enough. It is still a bad idea to even allow for an offline dictionary attack.

  • The server will have to store some information which is enough for a user to authenticate. This means that an attacker gaining temporary read access to the server's storage (e.g. a database dump through some SQL injection) may obtain passwords (or password-equivalent data) allowing him to impersonate users at very little cost. Better password schemes store on the server enough data to verify a password, but no more.

Making a proper, secure, authenticated medium for data transfer is not an easy task. If you really need to reimplement something yourself instead of using some SSL/TLS library, then do yourself a favor and implement a standard protocol for that, e.g. SSL/TLS. If you have qualms about certificate, consider TLS with SRP (no certificate at all, mutual client-server password-based authentication, not vulnerable to offline dictionary attacks).

Edit: about your clarification in your own edit: using the secret data (the password) as the key in HMAC, and the publicly known data (the challenge) as the data in HMAC, is theoretically much better than the reverse (HMAC was designed for the key to be secret); in practice, given the structure of HMAC, it would probably not much change security. Yet my points exposed above still apply.

4
  • But isn't it the same with SSL? Usually the login page is HTTPS, after the login is complete it's back to plain HTTP and a session cookie. At any rate I'm not trying to protect any further data transmission, it's just for the login. I think your latter points refer to password storage and not transmission, as I said earlier I actually use PBKDF2 for that.
    – Steffen
    Sep 6, 2011 at 4:14
  • 2
    @Steffen, No, it's not the same. No, you shouldn't transition back to HTTP; you should use SSL sitewide. That addresses these attacks. You say you're not trying to protect the subsequent data, but what you seem to be missing is that if you don't protect the actual data, then a MITM attacker can introduce malicious Javascript that completely defeats the security of your scheme (e.g., by keylogging the password and shipping it off to the attacker).
    – D.W.
    Sep 6, 2011 at 5:17
  • @D.W., I wasn't talking about my site and how I would implement SSL, just how most websites I use do it, and that is reverting back to HTTP and using HTTPS only to protect the login process. In those cases I would think the protection of subsequent data (in regards to MITM attacks) is the same. Of course I still protect any data against JS/SQL injections etc., it's just not transmitted encrypted (or rather hashed in my case) anymore. I don't think I should drop my scheme just because it doesn't protect against every possible attack. If I had SSL available, I would gladly use it.
    – Steffen
    Sep 6, 2011 at 6:25
  • 1
    @Steffen, yes, that is correct: sites that use HTTPS only for password entry and then fall back to HTTP are vulnerable to numerous attacks, including session cookie eavesdropping (aka Firesheep) and MITM attacks. That's why those sites are insecure and security folks recommend using sitewide SSL; sites that are using HTTPS only for password entry are "doing it wrong".
    – D.W.
    Sep 6, 2011 at 7:03
6

There is at least two big drawbacks with your challenge/response scheme:

  1. You have to store plaintext passwords (or plaintext-equivalents) on the server-side.

  2. You have to do password handling on the client-side, which means there is no quarantee that the client is executing "valid" piece of code to handle the password cooking. For example, if javascript was used to handle the "password cooking", you can not be sure if the client is executing malicious javascript, which (for example) sends the plain-text password straight to the attacker. This could happend by XSS, or perhaps the attacker was able to modify the HTTP-traffic before it reaches the client.

As a result, you could enhance your challenge/response scheme. Take a look at http://openwall.info/wiki/people/solar/algorithms/challenge-response-authentication Those algorithms address the "plain-text password storage problem".

But even with those "enhanced challenge/response authentication algorithms", the second drawback remains. And there is no portable/reliable way to deal it (except "SSL"). Possibly browser extensions could help to reduce some problems associated with javascript based "password cooking" operation (on the cliend-side), but it will not be as good as a secure HTTPS connection.

2
  • Oh, I just kept my question to a minimum, I store the passwords salted via PBKDF2 and compute that on the client-side before doing the HMAC for the challenge. What caught my eye though, your link says not to store Hs(password, salt), which I do. It would be an easy fix, but would you know the reasoning behind that? It strikes me as unnecessary. My question overall was less about the challenge/response scheme and more about HMAC and using the user's password (well, not password, but the key that is stored in the database) as the secret key. I was unsure if I didn't misuse it.
    – Steffen
    Sep 5, 2011 at 13:17
  • In Solar's challenge/response scheme, you can't store Hs(password, salt), because it is used in a XOR operation, and it must be unknown to the attacker. It is the whole point that even if the attacker steals the "password hash", he still can't use that information to log into the application. In your proposed scheme, the attacker can log into the application if he steals the "password hash" (even though he does not know the actual users password, but he can still log into the application).
    – timoh
    Sep 6, 2011 at 10:56
3

The question does not specify what is the threat model that it is defending against, but I suspect the scheme it proposes is not going to be sufficient in practice. My sense is that, in practice, in any threat model where plaintext passwords are a problem, the challenge-response proposal is not adequate, either.

In practice, in most situations where an attacker can eavesdrop on your communications, the attacker can also tamper with your communications and mount a man-in-the-middle attack. The most prominent example of this is communicating over an open wireless network, but others include DNS spoofing, client-side malware, malicious HTTP proxies, etc. And if the attacker can mount a man-in-the-middle attack, then the challenge-response proposal is not secure: the attacker can inject malicious Javascript that steals the password or does other nasty things.

Therefore, I think the challenge-response proposal provides a false sense of security, because it does not authenticate the content and code served by the server. I suspect that, instead of deploying your solution, you should be using SSL/TLS (i.e., HTTPS): if you have a need where cleartext-transmitted passwords are problematic, then you probably need SSL/TLS.

3
  • Well, I don't think my solution is in any way a replacement for SSL, I just don't want to send the user's password in cleartext for every login and a challenge system would mitigate at least that. In other words I'm not intending to protect them against active threads like man-in-the-middle attacks, I just don't want that every wannabe can sniff their password by simply eavesdropping on their insecure connection. So my question is solely if HMAC(msg=challenge, key=password) is good enough for that or if I'm misusing HMAC and shoud just do SHA(challenge+password) for example.
    – Steffen
    Sep 6, 2011 at 3:04
  • 1
    What I'm saying is that I don't think you've thought through the threat model. You are too narrowly focused on one attack, without realizing that there are other attacks that are just as serious and that aren't prevented by your scheme. Failing to think through the threat model is one of the most common mistakes made by folks new to cryptography, and I'm saying: you're making that mistake. As a result, I don't think your scheme will be secure in practice; I think it mainly provides a false sense of security.
    – D.W.
    Sep 6, 2011 at 5:15
  • Maybe I misspoke here, I didn't mean to say I don't care about other attacks, I meant that I made this thread just for this one issue, namely not sending the password as cleartext. Maybe have a look at my edit for clarification.
    – Steffen
    Sep 6, 2011 at 6:54
1

To authenticate a client, your approach sounds nearly right. It does, however, requires that you store plaintext password on your server. A small tweak to that is to store something derived from the password instead of the password itself. Then at the client side you derive the same info to feed in HMAC.

Be very careful though, this is NOT mutual authentication! The client does not authenticate your website and might be tricked/spoofed into giving his/her password.

And have you thought of replay attack?

How about off-line brute force attack?

What I am doing is to put a strong emphasis on the first part of your last sentence.

4
  • As for replay attacks, I tied the one-time challenge to an IP and it's only valid for one login, which I hope is enough? I know it's not perfect, I just want to make sure my "better than nothing" solution IS actually better than nothing.
    – Steffen
    Sep 5, 2011 at 13:38
  • How do you make sure that the challenge is used once only? The devil is in the details, so more details are better to hash it out. And since proxy is often used in corporate environments, tying a challenge to an IP could back fire when everyone seems to come from the same IP.
    – Nam Nguyen
    Sep 5, 2011 at 13:43
  • If the login is successfull the challenge is removed from the database. If the user sends the wrong password a new challenge is generated for the next try. In general every challenge is also only valid for one minute after creation. I hadn't considered the proxy problem, thanks for that, I'll have to think about that.
    – Steffen
    Sep 5, 2011 at 13:58
  • That sounds about right. Timestamping helps a lot in preventing replay attack. Also, the challenge size should be large enough so that its period is long enough to not repeat within its lifetime. I would not differentiate successful and unsuccessful cases, though. In both cases, I would just reset the challenge. I would go as far as reseting this challenge in every request (both before responding to a GET request and after processing a POST one).
    – Nam Nguyen
    Sep 5, 2011 at 14:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .