I shared a few emails back and forth with a reader last week who had an interesting problem. They had CFCs under web root that he did not want to be auto-described. If you don't know what I'm talking about, this is the feature within ColdFusion where if you request a CFC without a method you get a description of the methods and properties. This is normally protected by a login if your CF Administrator has either a normal or RDS password, as seen below.
So the question is - is there a way to disable or block this behavior? While it's not a security risk per se - you would need a valid login to see anything (*) - the reader wanted absolutely nothing to show up based on certain conditions. Here are a few options you can consider.
- Within your CFC you could actually detect the lack of a method call and add one yourself. I learned of this trick from Mark Drew.
if(!structKeyExists(url, "method")) {
url.method="helloworld";
} remote function helloworld() {
return "Hello Programs";
} }
component {
This code could use additional logic to check remote IP, time of day, whatever. Or - as the original reader wanted - you could return a header specifying a 404 error. How about another option?
- The first example works - but requires every CFC to be updated. You could add such logic to a base component easily enough - and in theory - your publicly accessible CFCs are probably a small subset of your total set of CFCs. But what about blocking it at the 'viewer' application? You may not know this, but the CFC describer tool is a set of CFMs/CFCs found within your /CFIDE/componentutils folder. Unlike most of the CF code that ships in /CFIDE these files are unencrypted. This means you can open up the Application.cfm file and do whatever you want. So for example, you can cflocate to a 404 handler based on whatever rules you have in mind.
p.s. Technically - just because you've locked down a CFC's auto descriptor does not mean you've really locked it down. Consider my CFC above where I auto set a method. If I add ?wsdl to the end I get the WSDL for the component. This will describe all the remote functions of the CFC. You could do something like this:
if(cgi.query_string == "wsdl") abort;
Which throws an error when CF tries to generate the WSDL code. The error may be preferable to you though. Would it would be nice if you could turn off the auto descriptor/auto Web Service support?
Archived Comments
I hate to even mention because I would never, ever do it, but you could technically add something like this to WEB-INF.cftags.component which every CFC extends.
How about IP restrict the /CFIDE/componentutils/ at webserver level?
I had mentioned that- but he wanted it to show up as a 404. Hence my thinking to use a CFIF and CFHEADER. Not sure if you can do that w/ IIS. You may be able to.
IIS 7.5 has built in URL rewriting so I'm sure something like this can be accomplished. Let me play around with it a bit and see what I can come up with.
I put it into a quick blog entry. Hope it helps.
http://cfsilence.com/blog/c...
For me, the best place to handle this in an application is the onCfcRequest Method of the Application framework... What do you think??
Interesting Damien! I didn't try that approach. Does it work?
Nope - just tested this and it did not work. I used this in my Application.cfc:
public void function onCFCRequest(string cfcname, string method, struct args) {
if(!structKeyExists(url, "method")) url.method = "foo";
}
I then requested /test.cfc and it didn't auto set the method.
Now this is interesting. While onCFCRequest didn't fire, onRequestStart did. So if I set url.method there, it does indeed block the auto descriptor.
What about the servlet mapping in the web.xml.
<servlet-mapping id="coldfusion_mapping_4">
<servlet-name>CFCServlet</servlet-name>
<url-pattern>*.cfc</url-pattern>
</servlet-mapping>
seems like removing that would work if you did not want url access to any cfcs.
One concern is stuff like http://www.coldfusionjedi.c...
but I don't know if that uses the .cfc mapping.
Needs testing, but might work.
I bet it would. Although I think the original guy I spoke to wanted to dynamically add this behavior - ie, if IP not in some range, do this.
FWIW IIS request blocking can handle IP address patterns.
As could an Apache rewrite rule block to send requests elsewhere unless their from the right place...
@Mike,
Nice idea and I very much like the web.xml servlet mappings.
This isn't really directed at you and is SOT, but I wish url-pattern was more flexible.
Currently this is valid (where "go" is an extension-less _file_ in webroot):
<servlet-mapping>
<servlet-name>CfmServlet</servlet-name>
<url-pattern>/go/*</url-pattern>
</servlet-mapping>
That's nice for handling these URLs in onRequestStart(): http://www.mysite.com/go/st...
(note there's no file extension, like .cfm, in the URL)
That works fine, if no other site on the server is serving URL-accessible content from a root-level directory named "go". Thus I'd much prefer if the servlet spec allowed this:
<servlet-mapping>
<servlet-name>CfmServlet</servlet-name>
<url-pattern>http://www.mysite.com/go/*<...
</servlet-mapping>
Thanks,
-Aaron
@Aaron,
I think you have a few options to route by domain:
1. Each site maps to its own web root and the JRun connector does look at the web root so that does get you close already. So /go* would always look at the relative site webroot.
2. Servlet Filters. Not sure what your end game is, but filters are a great way to do some conditional processing at this level.
3. URL rewrite in Apache or IIS. You could easily use rewrite rules to trigger any servlet mapping.
@Mike
Thanks very much for your follow-up. I'm trying to post a reply, but my comment keeps being blocked as spam. I've forwarded it to Ray, so hopefully he'll be able to post it for me.
Thanks again!,
-Aaron
@Mike,
Thank you very much for your follow-up. I'm unfamiliar with creating servlet "filters". But my issue with servlet "mappings" is 2-fold:
1. url-pattern cannot be domain-specific
2. config is only via /WEB-INF/web.xml
The problem with #1 is url-pattern could match a "folder" in one site, and match a "file" in another site.
Could a servlet filter allow the mapping to only be used when "_file_ exists"?
Example: mysite1.com/go?foo=bar versus mysite2.com/go/page.cfm
(mysite1.com has root-level extensionless file named "go", while mysite2.com has root-level directory named "go")
Currently, a /go/* mapping breaks mysite2.com's URL.
I have an idea for an enhancement to Application.cfc. I originally thought #1 would be a deal-breaker. However, if servlet mappings can be conditionally applied only to files, then there may still be a way.
If only this were possible:
<servlet-mapping>
<servlet-name>CfmServlet</servlet-name>
<url-pattern>/go/*</url-pattern>
<verify-file-exists>true</verify-file-exists>
</servlet-mapping>
Thanks again!,
-Aaron
By "I have an idea for an enhancement to Application.cfc", I was referring to something like:
THIS.extensionlessFileList = "/go,/foo/bar";
Where go, and bar, are extensionless CF files.
Not sure if this is possible, but just thought it'd be neat.
Thanks,
-Aaron
@Aaron
a servlet filter could work, however I think you are really trying to route traffic to the correct server or webapp, which puts me at a router, or web server. I'd look at doing a reverse proxy with some rewrite rules that will change context roots (weapps) based on domain.