I crashed my server a few minutes ago, and while not related, I discovered a little security flaw in my websocket demo that I thought would be fun to share with you guys. My mistakes should be your lessons, right? As with many mistakes, it involved something I knew could be an issue, I just had to find the time to confirm it really was. Before I tell you the flaw, let me show you the code and see if you can pick up the issue.
First, a bit of context. The code involved was for my websocket chat demo. It allows for, well, chat, and I wanted to ensure that the messages broadcast by users did not include any HTML. This is how I fixed it:
$("#sendmessagebutton").click(function() { var txt = $.trim($("#newmessage").val()); if(txt == "") return; txt = txt.replace(/<.*?>/,""); msg = { type: "chat", username: username, chat: txt }; chatWS.publish("chat",msg); $("#newmessage").val(""); });
Nice and simple, right? You take the input, trim it, strip the HTML, and then pass it to my websocket object. The message will now be "clean" of any HTML the user may have tried to send. That worked fine until I tried this...
So what happened there? As a user, I commonly will view source on web apps so I can see how they are built. I assume everyone does. I noticed how the chat system went through the code above. I also noticed how it simply packaged things up and passed it to a chatWS variable. Once I knew that, nothing stopped me from going into my browser console and executing the call manually.
Does that worry you? I hope so.
The moral of the story is - well - the same as it's always been. Don't trust client input. In this case though it didn't occur to me. Why? Because in our websocket implementation, you don't have to write any server side code. Your message just bounces out to all the clients.
Luckily this is easily enough to fix. In ColdFusion 10, you can associate a CFC with a websocket channel. One of the methods you can implement is "beforeMessage". This allows you to massage your messages before they go out. Here's how I corrected it:
public any function beforeSendMessage(any message, Struct subscriberInfo) { if(structKeyExists(message, "type") && message.type == "chat") message.chat=rereplace(message.chat, "<.*?>","","all"); return message; }
Make sense? (Btw, if you were around for when I crashed my server, this was certainly not why. I have a pretty good handle on why and will report back when I can.)
Archived Comments
If you're using CF then would it not be more secure to run any posts through a CF handler and just do something like
message.chat = htmlEditFormat(message.chat)
Um... did you read the entire post? :) I did do that.
Forgive my ignorance. What browser and plug-in are you running? Chrome and dev tools ?
Chrome and no plugin - dev tools are built in. All modern browsers have it, and of course Firebug is a good plugin for Firefox.
Hi Ray
Sorry about that. No I didn't read your post properly and I was definitely(!) typing while half asleep.
I wasn't clear where or how you were implementing your call to the beforeSendMessage() method.
Do you call it from within your jQuery script or is it handled implicitly as part of using the web socket? Your post kind of hints at the latter but I wasn't sure.
Sorry again.
Martin
It's the very first code snippet. That's the client side code I used.