views:

2231

answers:

10

I am using the twitter API to integrate twitter with my blog's commenting system. The problem with the twitter API and many other web APIs out there is that they require the user's username and password to do anything useful. I don't want to deal with the hassle and cost of installing a SSL certificate, but I also don't want passwords passed over the wire in clear text.

I guess my general question is: How can I send sensitive data over an insecure channel?

This is my current solution and I'd like to know if there are any holes in it:

  1. Generate a random key on the server (I'm using php).
  2. Save the key in a session and also output the key in a javascript variable.
  3. On form submit, use Triple DES in javascript with the key to encrypt the password.
  4. On the server, decrypt the password using the key from the session and then destroy the session.

The end result is that only the encrypted password is sent over the wire and the key is only used once and never sent with the password. Problem solved?

+8  A: 

Your method has a flaw - if someone were to intercept the transmission of the key to the user and the user's encrypted reply they could decrypt the reply and obtain the username/password of the user.

However, there is a way to securely send information over an unsecure medium so long as the information is not capable of being modified in transit known as the Diffie-Hellman algorithm. Basically two parties are able to compute the shared key used to encrypt the data based on their conversations - yet an observer does not have enough information to deduce the key.

Setting up the conversation between the client and the server can be tricky though, and much more time consuming than simply applying SSL to your site. You don't even have to pay for it - you can generate a self-signed certificate that provides the necessary encryption. This won't protect against man-in-the-middle attacks, but neither will the Diffie-Hellman algorithm.

Kyle Cronin
+13  A: 
  1. Generate a random key on the server (I'm using php).
  2. Save the key in a session and also output the key in a javascript variable.
  3. On form submit, use Triple DES in javascript with the key to encrypt the password.

This avoids sending the password in the clear over the wire, but it requires you to send the key in the clear over the wire, which would allow anyone eavesdropping to decode the password.

It's been said before and I'll say it again: don't try to make up your own cryptographic protocols! There are established protocols out there for this kind of thing that have been created, peer reviewed, beat on, hacked on, poked and prodded by professionals, use them! No one person is going to be able to come up with something better than the entire cryptographic and security community working together.

Chris Upchurch
A: 

So how is this any more secure? Even though you might have secured browser<>your server, what about the rest of the Internet (your server<>twitter)?

IMHO, it's unacceptable to ask for a username and password of another service and expect people to enter that. And if you care that much - don't integrate them until they get their act straight and re-enable OAuth. (They supported it for a while, but disabled it a few months ago.)

In the mean time, why not offer OpenID? Every Google, Yahoo!, VOX etc. account has one. People might not be aware of it but chances are really, really high that they already have OpenID. Check this list to see what I mean.

Till
A: 

When the key is sent between the client and the server it is clear text and subject to interception. Combine that with the encrypted text of the password and the password is decrypted.

Diffie-Hellman is a good solution. If you only need to authenticate them, and not actually transmit the password (because the password is already stored on the server) then you can use HTTP Digest Authentication, or some variation there of.

Jim McKeeth
+3  A: 
erickson
A: 

Doh! I didn't think about the fact that the key is sent down when the form is created and could potentially be paired up later with the encrypted password.

@Kyle Thanks, now I just need to find a javascript implementation of Diffie-Hellman. A quick google search turned up this implementation but not much else.

@Till I am using twitter's https URLs. I agree that OAuth would be ideal and twitter says it will have OAuth ready by the end of this year. But I would like to try to solve this problem now if possible since it would be useful for protecting other semi-sensitive data.

@erickson I feel like even a little stumbling block is better than nothing, since most traffic sniffers probably won't take the time to figure out if the encrypted blob is something valuable or not (unlike seeing username:bob;password:bob123 come over the wire). But you are right, I should not mislead the user into thinking it is secure.

dsims
A: 

I've implemented a different approach

  1. Server: user name and password-hash stored in the database
  2. Server: send a challenge with the form to request the password, store it in the session with a timestamp and the client's IP address
  3. Client: hash the password, concat challenge|username|passwordhash, hash it again and post it to the server
  4. Server: verify timestamp, IP, do the same concatenation/hashing and compare it

This applies to a password transmission. Using it for data means using the final hash as the encryption key for the plain text and generating a random initialization vector transmitted with the cipher text to the server.

Any comments on this?

Oli
This still doesn't prevent man-in-the-middle attacks.
Groo
A: 

How can I send sensitive data over an insecure channel

With a pre-shared secret key. This is what you attempt in your suggested solution, but you can't send that key over the insecure channel. Someone mentioned DH, which will help you negotiate a key. But the other part of what SSL does is provide authentication, to prevent man-in-the-middle attacks so that the client knows they are negotiating a key with the person they intend to communicate with.

Chris Upchurch's advice is really the only good answer there is for 99.99% of engineers - don't do it. Let someone else do it and use their solution (like the guys who wrote the SSL client/server).

I think the ideal solution here would be to get Twitter to support OpenID and then use that.

Brian
A: 

An ssl certificate that is self-signed doesn't cost money. For a free twitter service, that is probably just fine for users.

Marcin
A: 

TO OLI

In your approch for example i'm in the same subnet with same router, so i get the same ip as my collegues in my work. I open same url in browser, so server generates the timestamp with same ip, then i use tcp/ip dump to sniff the hashed or non hashed password from my collegues connection. I can sniff everything he sends. So i have all hashes from his form also you have timestamp(my) and same ip. So i send everything using post tool and hey i'm loggen in.

bad_man