By Peter Bell

When CFQueryParam is NOT Required

There are a number of performance benefits to cfqueryparam which are worth revieweing and understanding, but one of the biggest reasons to use cfqueryparam is to avoid SQL injection attacks. The interesting thing is that it is only necessary to do that for strings.

Unlike a simple RegEx, cfqueryparam actually tells the database that this is a parameter which stops injected SQL from being executed even if it includes the traditional SQL characters for ending a command and adding a drop table (or whatever).

However, if you think about it, the only time this is really important is if you are saving to a string based field (varchar, nvarchar, text, ntext, char, nchar, etc.). For bits, floats, integers, datetimes and other relatively constrained data types, it is perfectly valid to just use a RegEx to strip any unacceptable characters before calling the db script.

I personally tend to prefer this approach as I'd rather get my own error from my validation library than having to catch, parse and handle the error thrown by the db library (as an aside, does anyone have sample code that will catch common database errors thrown by a cfquery in a try/catch block and parse them so you can throw something useful in terms of the element of the SQL that the db didn't like? I *think* this is a hard problem to solve but am not sure - heck I don't even know if the syntax of the error message is consistent across db drivers).

Not to say you *shouldn't* use cfqueryparam, but just that you don't necessarily have to except for when saving to string type fields (varchar, nvarchar, text, ntext, char, nchar, etc.). Of course this means you MUST validate every field before saving it to a db, but with custom data types and a simple validation library this is should be a default behavior for all of your fields all of the time as it takes almost no effort.

Any thoughts/opinions?!

Comments
Remember that cfqueryparam serves more purposes than simply to protect against sql injection, it also allows you to use a prepared statement and all related caches (both on the ColdFusion side and on the SQL side where the prepared statement is matched with a cached execution plan).
# Posted By Brian Rinaldi | 2/4/07 5:02 PM
Hi Brian,

Agreed 100%. I mentioned the performance benefits of using cfqueryparam, but I'm always leery of premature optimization, so I wouldn't use cfqueryparam for performance reasons unless I found a performance bottleneck with my db queries.

And in case you're wondering why I wouldn't just use cfqueryparam all the time, it is a pain when you're generating code as I haven't been able to "eval" it so I have to actually generate queries, write them to the file system and then call them (unless I'm missing something). Obviously this is only a one time hit, but I really don't like having the extra code lying around bulking up the code base unless I need it.

To be fair I haven't really tried to find a way to run cfqueryparam in dynamically concatenated SQL, so if anyone has figured that out, please let me know, but I don't believe it's "eval"'able which is a pain given how I create my code!
# Posted By Peter Bell | 2/4/07 5:14 PM
With the current cfquery param structure, it can be a complete PITA to get dynamically evaluated SQL to use them.

Often I end up having to generate my SQL as a array, broken down by each param I want to enter... so I end up build an array of Structs with describes my SQL, and then inside my <cfquery> tag, I loop around my query and push out my query.

It works, but it does feel like a bit of a double handle. Not much else you can do however.
# Posted By Mark Mandel | 2/4/07 5:26 PM
Oh cool - so you *can* dynamically eval it - it's just a bit of a dance? Is there a core file I could look at to check out how you do this?
# Posted By Peter Bell | 2/4/07 5:29 PM
In case anyone DOES need dynamically generated SQL that uses cfqueryparam, Mark (the Genuis) Mandel just pointed me to some working code you could snarf:

http://transfer.riaforge.org/index.cfm?event=page....

Check out line 43. I think this proves that the expressiveness of a language DOES affect how easy it is to solve problems in, but this is a pretty cool little snippet for dynamic cfqueryparams.

Thanks Mark!
# Posted By Peter Bell | 2/4/07 5:40 PM
Peter,

That's very cool, but why not just set all the attribute values as variables in the cfqueryparam? I mean, it looks like the CASE statement's only purpose is to set the proper cfsqltype. Just curious if I'm missing something....

/ejt
# Posted By Edward T | 2/5/07 9:31 AM
What if you want that code to work for n-attributes where you don't know until runtime what the list of attributes would be? Looks to me like the code allows you to have n-attributes where the number, names and data types of the attributes don't need to be known until runtime. That's why I'd use a case statement.

The problem to solve: write a cfquery that will save any object with n-attributes using cfqueryparam for each attribute. Can't think how to do that other than using Marks approach.

Am I missing something?
# Posted By Peter Bell | 2/5/07 9:41 AM
I actually use the same basic approach as Mark. I use an array where each item can either be a string of SQL or a struct that represents a cfqueryparam tag.

DataMgr actually exposes this approach using the runSQLArray() method. You could obviously take that code out and use it independently.

Interesting to see that Mark an I came upon similar solutions separately.
# Posted By Steve Bryant | 2/5/07 9:52 AM
Hi Steve,

Interesting! I guess not surprising just because there are only so many possible solutions out there. It is like using inheritance for extending generated components - one of those good ideas that seems to keep on getting re-invented!
# Posted By Peter Bell | 2/5/07 9:56 AM
Yep! It is encouraging. If someone as smart as Mark came to the same conclusion, it must not have been too bad an approach.
# Posted By Steve Bryant | 2/5/07 10:04 AM
awww... shucks.. you guys are making me blush.

Pretty much all of the Transfer SQL stuff works by breaking things down so that they can be later re-evaluated.

You don't really have a choice.

What alternative methods are there, if you want to use cfqueryparam?
# Posted By Mark Mandel | 2/5/07 6:25 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.