In a perfect world all user input data would conform to the max length of the database fields that you want to put them in right? As we all know, we don’t live in a perfect world, so you as a developer are forced (hopefully) to build in several layers of redundancy in your data validation methods. The steps below outline some pretty basic concepts when it comes to handling string input from an ext app using cold fusion as the back end language.
You should be using cfqueryparam for all of your input by now, but just in case you are not consider the following example from Adobe itself.
You have a table called sometable and you are updating somelement based on passing someprimamrykey to the server. On the other side you have written the following
<cfparam name=" somelement " default="" > <cfparam name=" someprimamrykey " default=""> <cfquery name="my_cool_query" datasource="big_db" > UPDATE my_table SET some_column = '#somelement #' WHERE my_primar_key = # someprimamrykey # </cfquery>
Now let’s plug in some values we’ll replace somelement with ‘Acme Incorporated’ and replace someprimarykey with an integer like say 7. So far so good, right? Of course, this is all taken from the query string below that is visible for all to see.
https://my_site.org? somelement= Acme%20Incorporated& someprimamrykey=7
Now since we have a keen eye for detail we immediately notice that the primary key looks like an integer and could be used in the WHERE statement of the query which is – where else but at the end. Knowing this we enter the following value in the textbox on our site that corresponds with someprimarykey, ’7 DELETE from user_table’.
We’ll type in the following url to do the trick:
https://my_site.org? somelement= Acme%20Incorporated& 7%20DELETE%20from%20user_table
Now the query that will get run is below:
UPDATE my_table SET some_column = 'Acme Incorporated' WHERE my_primar_key = 7 DELETE from user_table </cfquery>
Uh-oh we just deleted all the users, of course this assumes that we know the name of the user table but say you are running some open source content management system, then all of the names are known variables, right?
How can we stop this from happening?
Let’s take the following steps on the client side in our Ext code:
Make sure you set the maxLength AND the enforceMaxlength config options in your extjs code to stop the user from having the ability to enter strings of any length.
If you want to restrict the input to alpha numeric only use the built in Ext.Vtype in the text fields vtype config option. If you need to get fancy, or want to make sure that other characters get let in like those in foreign languages that are not a-z you could look into writing your own vtype and adding it to this config option.
Great, now that you have all of your client side validation in place lets work on making the server side is just as secure.
Always use cfqueryparam with the maxlength attribute set to the same maxlength as the database element and the ext maxlength above, this will make sure that cold fusion throws an error when someone tries to pass in a string that is longer than the specified maxlength. Why, you might ask, we already took care of that on the client side, didn’t we? Well, chances are you are still passing the variable and someone could inject their own value and pass it directly to the server, for instance, by modifying the URL above like we just did in the example.
Let’s see what happens to the input in the example above if we were to use cfqueryparam instead of just outputting the vale in the query directly, as in the code below the whole query would have failed due to the fact that the Delete statement was tacked onto the end of the primary key which is an integer.
UPDATE my_table SET some_column = <cfqueryparam cfsqltype="cf_sql_varchar" value="Acme Incorporated" maxlength="20" /> WHERE my_primar_key = <cfqueryparam cfsqltype="cf_sql_integer" value="7 DELETE from user_table " /> </cfquery>
If this had been a where clause looking at a string value instead of an integer, no damage would have been done as the cfqueryparam tag would have escaped the output with single quotes which would have meant that the SQL would have evaluated the whole string.