Your security lesson for the day - Console is the MCP

This post is more than 2 years old.

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.)

Raymond Camden's Picture

About Raymond Camden

Raymond is a developer advocate for HERE Technologies. He focuses on JavaScript, serverless and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Martin posted on 2/24/2012 at 6:38 PM

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)

Comment 2 by Raymond Camden posted on 2/24/2012 at 7:15 PM

Um... did you read the entire post? :) I did do that.

Comment 3 by Dan posted on 2/24/2012 at 7:31 PM

Forgive my ignorance. What browser and plug-in are you running? Chrome and dev tools ?

Comment 4 by Raymond Camden posted on 2/24/2012 at 7:36 PM

Chrome and no plugin - dev tools are built in. All modern browsers have it, and of course Firebug is a good plugin for Firefox.

Comment 5 by Martin posted on 2/28/2012 at 2:19 PM

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

Comment 6 by Raymond Camden posted on 2/28/2012 at 4:37 PM

It's the very first code snippet. That's the client side code I used.