Friday, January 16, 2009

Chat Hacking, Part II

So, got it to work. Turns out we were both right: Danny was correct in that we weren't using the JSJaC library properly, and I was right in that the server detected our switcheroo and didn't want to talk to us.

Firstly, we discovered there's an internal (but public) method on JSJaC's connection object called inherit, which allows you to utilize an existing http-bind session when you fire up the chat engine. That turns out to be the right way to do things. It expects a number of arguments passed in an argument object, three of which are vital to convincing the server that you are who you say you are:

sid: (Session ID) This is generated by the server and sent in the connection phase, we already had this working fine in Perl, so no problems here.

key: The key is a hex-encoded sha1 hash sequence, and it's used to verify that each subsequent request comes from the same client. How? Well, each new key is the sha1 hash of the previous key. If you transmit the wrong key, the server barfs on you.

rid: (Request ID) This is simply a sequential number, but it's important with respect to the key. If your request ID is not in lock-step with your key sequence, the server again will barf on you.

Getting the key right was the trickiest part, but not too bad. Essentially, JSJaC by default generates a list of 16 keys at a time to use. Since we weren't initializing the session using JSJaC, we instead had Perl initialize those keys and use the first few to establish a connection. The key list then gets injected in to the web page where JSJaC can pick it up. As long as there are no fencepost errors, the whole sequence proceeds along without a hitch, and the server happily talks to the JavaScript.

It's actually not as fragile as we were afraid it might be, since the session/key/rid setup makes sure that each session is unique and can only be utilized in JS by the CGI that initiated it. And it makes sure that all the credentials required for login are safely tucked away on the server side, where clients can't see them at all. Now all we have to do is tweak (read: restrict or rewrite) the JWChat interface a little to give it fewer features, and add a bit of conversation logging, and we've basically accomplished what we set out to do.

Which means we can have anonymous clients talking to our people on our internal chat server, in a controlled environment and without compromising any credentials.

@Steve: Yes, we considered that once we figured out that the keys were part of the problem. It's true we only want to use a limited subset of the library by restricting the chat features, but we don't want to cut back on security provided by JSJaC. So since you decided to support it in the library, we thought it best we take advantage of it.