Sunday 8 December 2013

Something I'd not looked at before: ColdFusion security sandboxes

Russ posted a question on Twitter yesterday:

I have to concede this is part of ColdFusion I have never looked at. He didn't get any useful responses over night, so I decided to check whether I could either confirm the behaviour he was seeing, or declare "works OK on my machine".

Firstly, I had to find out how to even do this "sandbox" stuff. I couldn't recall seeing anything about it in CFAdmin, but there it was:

I switched that on - necessitating a ColdFusion restart - and set up a sandbox dir.

I created it in C:\webroots\shared\git\blogExamples\coldfusion\sandbox (this becomes relevant, shortly), and for that directory switched off access to all the tags and functions which one can monkey with (it's not all of them, for some reason: Adobe second-guessing what we want to do again, I guess).

Then I wrote a quick file, thus:

// test.cfm
files = directoryList(expandPath(".."), true, "query");

This was in the above dir.

In theory this should be blocked for a number of reasons:
  • I've blocked expandPath();
  • and directoryList();
  • and the code should not have access to the parent directory.
So I browsed to test.cfm and... it ran as per usual. Hmmm. So on the face of it, this would bear out what Russ was seeing. However I was not yet convinced I actually knew what I was doing. So I cranked up CF9 and did the same thing, and that didn't seem to work either (ie: the code still ran fine, rather than being blocked)! So I was doing something wrong.

Fortunately I had a suspicion that ColdFusion wasn't aware of how I've organised my file system... C:\webroots\shared\ is a physical directory, sure. However that's not how my ColdFusion 10 instance accesses it. My CF10 webroot is C:\apps\adobe\ColdFusion\10\cfusion\wwwroot\, and within that I have a directory link "shared" pointing to C:\webroots\shared\

IE when I installed CF10, I did this in its webroot:

mklink /d shared C:\webroots\shared

This is just the easiest way I know of of having all my CFML instances / installs accessing the same dir on the file system. However this is a fairly low-level file system operation, so I think it's completely legit for CF to not realise that when I told it to sandbox C:\webroots\shared\git\blogExamples\coldfusion\sandbox, that that's the same directory as what it knows as C:\apps\adobe\ColdFusion\10\cfusion\wwwroot\shared\git\blogExamples\coldfusion\sandbox.

For a moment I thought maybe it could work it out by looking at the canonical path of the two (hoping it'd be the same), but no:

<!--- canonicalPaths.cfm --->
<cfset actualPath = "C:\webroots\shared\git\blogExamples\coldfusion\sandbox">
<cfset linkedPath = "C:\apps\adobe\ColdFusion\10\cfusion\wwwroot\shared\git\blogExamples\coldfusion\sandbox">

Actual: #actualPath# => #createObject("java", "").init(actualPath).getAbsolutePath()#<br>
Linked: #linkedPath# => #createObject("java", "").init(linkedPath).getAbsolutePath()#<br>

This outputs:

Actual: C:\webroots\shared\git\blogExamples\coldfusion\sandbox => C:\webroots\shared\git\blogExamples\coldfusion\sandbox
Linked: C:\apps\adobe\ColdFusion\10\cfusion\wwwroot\shared\git\blogExamples\coldfusion\sandbox => C:\apps\adobe\ColdFusion\10\cfusion\wwwroot\shared\git\blogExamples\coldfusion\sandbox

Java doesn't see the difference either. Having a look around there's probably some stuff in java.nio.files.* which might help with this, but I don't care enough to find out.

Anyway, I added in the directory name from CF's perspective as a sandbox, and I started getting expected results:

Error Occurred While Processing Request

Security: The requested template has been denied access to expandpath.

The following is the internal exception message: access denied ("coldfusion.runtime.FunctionPermission" "expandpath")
The error occurred inC:/apps/adobe/ColdFusion/10/cfusion/wwwroot/shared/git/blogExamples/coldfusion/sandbox/test.cfm: line 3
1 : <cfscript>
2 : // test.cfm
3 : files = directoryList(expandPath("."), true, "query");
4 : writeDump(var=files);
5 : </cfscript>

I gave permissions for expandPath() to run, and the error changed to this:

Security: The requested template has been denied access to getbasetemplatepath.

I guess expandPath() calls getBaseTemplatePath() internally. I would have expected that had I said "let expandPath() run" then CF would take care of any dependencies, but it seems not. Slightly slack here. So I give permission to getBaseTemplatePath()to run too, and I am still getting expected results:

Security: The requested template has been denied access to directorylist.

And if I give perms to directoryList() to run, I get this:

Security: The requested template has been denied access to C:/apps/adobe/ColdFusion/10/cfusion/wwwroot/shared/git/blogExamples/coldfusion.

The following is the internal exception message: access denied ("" "C:/apps/adobe/ColdFusion/10/cfusion/wwwroot/shared/git/blogExamples/coldfusion" "read")
ColdFusion cannot determine the line of the template that caused this error. This is often caused by an error in the exception handling subsystem.

This too is correct.

So I'm confident that at least at a superficial level, ColdFusion 10 sandboxing works.

Have any of you lot had much experience with sandboxing, and perhaps can help Russ? (If he still needs it, that is).