In Using WebSocket in point-to-point communication in Adobe ColdFusion 10 Dev Guide, the javascript object mysocket
created by <cfwebsocket>
can call an invoke()
method that can literally invoke Any public method on Any CFC from JavaScript.
How is this Not a security risk? How shall a cfc / function protect against being invoked by websocket?
1. Create a CFM page index.cfm.
<script type="text/javascript"> function msgHandler(msgobj){ var txt = document.getElementById("myDiv"); var message = ColdFusion.JSON.encode(msgobj); txt.innerHTML += message + "<br >" + "<br>"; } function invokecfcfn(){ var fname= document.getElementById("fnname").value; if (fname == "f2") { alert("f2 selected"); mysocket.invoke("mycfc", "f2", ["echo"]); } else mysocket.invoke("mycfc", fname); } </script> <cfwebsocket name="mysocket" onmessage="msgHandler"/> <form> <select id="fnname"> <option>f1</option> <option>f2</option> <option>f3</option> </select> <input id="invokefn" name="invokefn" value="Invoke CFC function " type="button" onclick="invokecfcfn();"> <div id="myDiv"> </div> </form>
2. Create a CFC mycfc.cfc that contains the function called from the client page.
<cfcomponent> <cffunction name="f1" > <cfreturn "Message returned from f1"> </cffunction> <cffunction name="f2" returntype="string" > <cfargument name="arg1" type="string" required="true" > <cfset msg= "Message from wsssendmessage of f2 which you called with arg " & arg1> <cfset wssendMessage(msg)> <cfreturn "Message returned from f2"> </cffunction> <cffunction name="f3" > <cfthread action="run" name="t1" > <cfloop index="i" from="1" to="10"> <cfset sleep(20000)> <cfset wssendMessage("Message #i# from wsssendmessage of f3 #now()#")> </cfloop> </cfthread> <cfreturn "Thread initiated in f3"> </cffunction> </cfcomponent>
EDIT: not Any function, private function returns:
{
"clientid":39550088,
"ns":"coldfusion.websocket.channels",
"reqType":"invoke",
"code":4001,
"type":"response",
"msg":"The method f1 was not found in component mycfc.cfc."
}
UPDATE:
I tried moving mycfc.cfc
to /com
(outside of webroot) and added a mapping to /com
and the functions can STILL be successfully invoked.
UPDATE: July 3, 2013
The Adobe Product Security Incident Response Team (PSIRT) is aware of this issue and is actively engaged with the ColdFusion Product Team to release a fix.
http://blogs.coldfusion.com/post.cfm/coldfusion-10-websocket-vulnerebility
UPDATE: July 9, 2013
Adobe has released a security hotfix for ColdFusion 10 for Windows, Macintosh and Linux. This hotfix addresses a vulnerability (CVE-2013-3350) that could permit an attacker to invoke public methods on ColdFusion Components (CFC) using WebSockets.
http://www.adobe.com/support/security/bulletins/apsb13-19.html
I don't think you can fix this with ColdFusion as it currently stands (update: this was written prior to ColdFusion 10.0.11 being released; the issue has now been resolved by 10.0.11). I don't think Bruce's CFML-based answer - whilst it or a variation thereof would work - is really feasible in the real world.
I would probably fall back to using firewall rules: web socket requests come in on a specific port, so you could have a set of rules around requests on that port, and which methods are allowable over it.
This is not a great solution, but it's probably the most expedient given the situation.
I pointed to my research on the CF side of things in a comment to your original question, but it's probably better being linked to from here: "Web socket security issue: risk assessment & findings"
Coldfusion 10 websockets invoke feature does seem broken to me after actual testing and further investigation of the new documentation pages and other projects (this thing is complicated!). I spent over an hour trying to get something to execute before the invoked function is run. I can't!
There are new "channel listener functions" documented here: http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSe61e35da8d318518767eb3aa135858633ee-7ff9.html
However, the documentation clearly states that the "invoke" feature doesn't have a listener function. It also appears Application.cfc or the cfc listener don't execute on each request at all when invoke is run.
This seems like a design flaw. The language needs more event listeners or you can't use websockets without adding security to every function in your application.
The security within each function could be done like the code below, but it is not very practical to modify every function in an application:
<cfscript>
local.meta=GetMetaData(this[url.method]);
if(not structkeyexists(local.meta, 'access') or local.meta.access NEQ 'remote'){
throw("Function access must be set to remote.");
}
</cfscript>
You could also consider using a web server proxy in front of Coldfusion and use regular expressions to verify the request information so that only the websocket portion of your application has to be open on the public websocket port. Nginx 1.4+ has support for websocket proxying now: http://nginx.org/en/docs/http/websocket.html Note: I have not tested using nginx websocket proxy yet. If it works, this would be a far easier solution.
Adobe has released a security hotfix for ColdFusion 10 for Windows, Macintosh and Linux. This hotfix addresses a vulnerability (CVE-2013-3350) that could permit an attacker to invoke public methods on ColdFusion Components (CFC) using WebSockets.
http://www.adobe.com/support/security/bulletins/apsb13-19.html
Invoking public method after Update 11 is applied will return "code":4001
& "msg":"The method f1 in component mycfc cannot be accessed remotely."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With