Ask a Jedi: Block access to an include files

This post is more than 2 years old.

Devon asks:

I am using your custom tag technique to manage the layout of my site. I'm not sure if the fact that the cfinclude is in a tag makes any difference but I am looking for a way to stop in include file from being accessible if navigated to directly. One thought was to move the cfoutput tags out of the included files and into the layout...but it seems then i need to cfoutput around all variables...and then they are displayed if the page is browsed directly.

The other option is to set a variable in the request scope that I then check in all included pages to make sure it was called from within a layout. So far this is what I am going with. Am I overlooking a feature that does this better?

So the obvious answer is that if you don't want a CFM available directly, just move it out of a web root. I typically put all my includes in an include folder, outside of web root. If /app is a ColdFusion mapping pointing to my application root, I'd then use

<cfinclude template="/app/includes/slovenlytrull.cfm">

But what if you are on a host and your root folder is your web root? One simple thing to do is check the current versus base template path. Consider this file that is included:

<cfif getBaseTemplatePath() eq getCurrentTemplatePath()> Direct execution denied. <cfabort> </cfif>

This is the include file - running fine.

The getBaseTemplatePath function returns the files 'base' page. This just means that if the file was an cfinclude or custom tag, you get the file that called it, not the file itself. The getCurrentTemplatePath function will return the file itself.

If you hit the included filed directly, then both functions will return the same value. Therefore I output an error and abort the request.

Again though the number one thing I'd recommend is simply moving the file out of web root.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, 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 Sean Coyne posted on 3/6/2008 at 6:26 PM

Why not put them all in an includes folder then add an Application.cfm file with just a <cfabort />. This will work on shared hosting as well.

Comment 2 by Raymond Camden posted on 3/6/2008 at 6:28 PM

Dude, it's funny. I was away from the keyboard (getting ready to bring the kids to school) when I remember the App.cfc/cfm method. So yes, that is another way of doing it. Although I'd probably just do it in my App's root Application.cfc file. In onRequestStart you can look for /includes in the template and if it exists, block it.

Comment 3 by Devon posted on 3/6/2008 at 7:28 PM

Will be using this in a mini inhouse framework which is very much geared toward drag and drop a site and edit the css for guys who dont know to much CFML. So moving outside the webroot is not an option,since shared hosting will be the most likely candidate for the simple sites this allows.

Thanks Ray, this helps.

Comment 4 by Ben Nadel posted on 3/6/2008 at 7:50 PM

I have been using a system that works great for me. All non-public files start with underscores. Example:

_header.cfm
_footer.cfm

Then, in the App.cfc/cfm I check to see if the requested page starts with an underscore and if so, I throw an error (or treat otherwise).

This works great on two levels. On one level, its an ultra easy way to limit file access. But, almost more importantly, it makes a really obvious statement about the file to anyone who is going to be working on it. Is this a public file?? Does it start with an underscore? If yes, then no, not a public file. I love me some explicit style.

Comment 5 by Raymond Camden posted on 3/6/2008 at 8:00 PM

Until a new developer forgets the _. ;)

Which also applies to the solution I suggested of checking getbasttemplatepath.

These are _all_ hacks. Just best to put the files outside of web root. :)

Comment 6 by Will B. posted on 3/6/2008 at 9:41 PM

I saw another system of doing this in a free (PHP-based) CRM tool called SugarCRM. I dug through the files for grins. It contained a set of flags that checked something like a request scope variable. Meaning, if the primary page was properly executed (think index.cfm in an MVC setup), then a request flag was set, like "request.properlyRun", whatever. Then each page checked that flag and wouldn't execute if called directly.

- Will B.

Comment 7 by Adam Bielawski posted on 3/6/2008 at 9:44 PM

Hi Ben,

I'm a mere novice in CF, I usually prefix my includes with the underscore, how do you check?

I hope I'm not too mere mortal for this blog.

Adam

Comment 8 by Raymond Camden posted on 3/6/2008 at 9:48 PM

Adam, this blog is for people of all skill levels. :)

I'll answer the q, even though it was to Ben. In OnRequestStart, you have access to the name of the template being requested, ie

/index.cfm

/foo/goo.cfm

Etc. You can get the filename by using list functions:

filename = listLast(arguments.template,"/")

You can then see if the first char is a _

if(left(filename,1) is "_")

Comment 9 by Ben Nadel posted on 3/6/2008 at 9:48 PM

@Adam,

No problem, it's pretty easy:

<cfif (Left( GetFileFromPath( GetBaseTemplatePath() ), 1 ) EQ "_")>

... throw error, or include a different file (ex. index.cfm).

</cfif>

Comment 10 by Ben Nadel posted on 3/6/2008 at 9:49 PM

Ooops :) Me and Ray answered at the same time :)

Comment 11 by Adam Bielawski posted on 3/6/2008 at 9:52 PM

Cool thanks guys, I will have to try this out this weekend. I am not new to CF, just don't have time to reinvorce my skills anymore at my current job. But those are the phases in life, so all it during those weekends at home trying to get my site(s) more interactive.

Adam

Comment 12 by Geoff posted on 3/7/2008 at 12:26 AM

http://livedocs.adobe.com/w...

This is worth a read, if your web host allows you to access a level above your wwwroot.

You can put all your includes outside of the web root and just <cfinclude template="../extensions/includes/blah.cfm" />

And if you like the tag library layout, you can <cfimport> some folder or other outside the webroot.

<cfimport prefix="blah" taglib="../extensions/customtags/" />
<blah:nav>
<h1>Hello!</h1>
</blah:nav>

Comment 13 by Robb posted on 3/7/2008 at 1:41 AM

All of these suggestions are great to have depending on circumstance but don't forget about FTP security. HTTP access obviously is important to manage but having someone attack your FTP just plain sucks even if they don't get in. If you can control your FTP address use an ip address that is not related with your sites and try not to use ftp.sitename.com.

Just my 2 cents and thanks for all the great suggestions.

Comment 14 by dc posted on 3/7/2008 at 2:21 AM

+1 for the underscore.

I then do the security at the web server level and I can use the underscore method for any file type that should not be served directly.

As for it being a hack that a new developer might miss, surely you have documentation and coding guidelines :)

Comment 15 by DanaK posted on 3/7/2008 at 6:51 PM

Just a side note, there is a slim chance that using hyphens or underscores in your filesnames can cause some unforseen issues in a very small number of cases.

IIS 6.x applies encoding to hyphens and underscores in all its courtesy redirects (at least it used to?). The 'best practice' I have read in the past was to avoid using them in folder structure and file naming in a production environment where they will be a part of a direct url request.

Comment 16 by Raymond Camden posted on 3/7/2008 at 6:55 PM

Interesting tip there Dana - although - if it WERE to block a URL request, or make it harder, that would actually be helpful in this situation. ;)