Via this question I've been told to start using cfqueryparam for my data, to prevent SQL injection attacks.
How do I use it for my forms? Right now I've been going over Ben Forta's book, Vol 1 and been passing data to my form, then to a form processor that calls a CFC. The CFC takes them in as a cfargument then injects that into the database with any type="x" validation.
Io use the cfqueryparam, I use that on the query itself and not even declare cfargument?
You can still use a CFC, but remember that string data passed as a function argument will still need <cfqueryparam>. Here is an example:
<cffunction name="saveData" access="public" returntype="void" output="false">
<cfargument name="formVar" type="string" required="true" />
<cfquery name="LOCAL.qSave" datasource="myDSN">
insert into myTable (col1)
values (<cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.formVar#" />)
</cfquery>
</cffunction>
The important habit to get into is to always use <cfqueryparam>, even in CFCs.
Here is some more info on those edge-cases where you might find it hard to use <cfqueryparam>.
Hope that helps!
Related
I'm trying to implement CF10 ORM to a current project but there seems to be a problem between my DAO and my table (11g).
I pass in a bean in the call to this DAO method:
<cffunction name="saveData" access="public" returntype="void">
<cfargument name="DataBean" />
<cfset entitySave(arguments.DataBean)/>
</cffunction>
This should write it to the table. If I dump the arguments from inside this method the bean is populated, but nothing writes. There's no errors being thrown so nothing immediately obvious.
Can anyone tell me where I might be going wrong?
I've started using ORM in Coldfusion 9, but I'm running into an issue in which I've got a CFC that is set to persistant=true so that when I run myCFC.init() the default values of the properties are assigned - but I don't want to use this CFC with ORM.
The problem is that Coldfusion throws the error "Table myCFC defined for cfc myCFC does not exist."
Is there a way I can get my application to ignore certain CFCs? Or only pay attention to specific CFCs, other than persistant=true
Alternatively, can I get my default property values to take effect without making the component persistent
Alternatively, can I get my default property values to take effect without making the component persistent?
Yes, just set them in your init() method.
<cfcomponent name="person" persistent="false" output="false">
<cfproperty name="gender"><!--- Non-persistent CFC: you can't set a default here --->
<cffunction name="init" output="false>
<cfset variables.gender = "m"><!--- Set the default here --->
</cffunction>
</cfcomponent>
You would also need to do this in your persistent CFCs for any complex or dynamic value defaults (e.g. an array or the current date), since you can only set simple default values (e.g. a literal string or integer) in property declarations.
<cfcomponent name="person" persistent="true" table="persons" output="false">
<cfproperty name="gender" default="m"><!---Persistent CFC, so this simple default will be set --->
<cfproperty name="dateCreated"><!---You can't set a default dynamic date value --->
<cffunction name="init" output="false>
<cfset variables.dateCreated= Now()><!--- Set the current datetime here --->
</cffunction>
</cfcomponent>
Any code you place between your opening and the first will be executed. I'm assuming your using CFproperty tags to set you defaults. Instead, use this structure:
<cfcomponent name="aCFC">
<!---
|| Psuedo Constructor code: this code runs when the object is created.
||--->
<cfset defaultVar_1 = "default value">
...etc
<cffunction name="firstFunction">
...
</cffunction>
</cfcomponent>
I'm trying to setup my first application.cfc file.
I tried to invoke variables on an "event-basis" like so:
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfparam name="Application.RootDir" default="/">
<cfreturn true>
</cffunction>
<cffunction name="onSessionStart" returnType="boolean" output="false">
<cfparam name="Session.activeSession" default="Yes">
<cfparam name="Session.activeLogin" default="No">
<cfreturn true>
</cffunction>
I thought this would work nicely, but turns out, it does not, because I need to declare everything before, like so:
<cfparam name="Application.RootDir" default="">
<cfparam name="Session.activeSession" default="">
<cfparam name="Session.activeLogin" default="">
My Question:
Why should I use CF-events for declaring variables. If I need to declare outside of an event anyway, I could save myself a line of code and declare&assign the inital value? Am I doing it wrong or are events only for assinging not for declaring?
Thanks for input!
What do you mean by "before" ("declare everything before")? Before what? The onApplicationStart() handler is the first thing run when an application starts, and the onSessionStart() handler is the first thing run when a session starts. So in the context of applications and sessions being established, there is no "before". I think you need to show us more code: eg some code that demonstrates them "not working".
That said, you don't show us the pseudo-constructor section of your Application.cfc, so it's impossible to tell what problems you have there, if any. But you need to enable session management before sessions will work, and you possible need to name your app before either application or session variables will stick, too (although they might just work with the nameless application too? Even if they do, it's best to name your app).
Lastly - and this will have no bearing on whether your variables are set or not, but you should be using <cfset> when setting variables, not <cfparam>. Both have the same effect here, but the former is the correct tool for the job.
A form field value like 45,234 is to be inserted into the DB as 45234. When I try to do insert for 45,234, all it gets into the DB is 0.Note:- I am able to insert 45.234as 45.234 in the SQL DB.
The form field is named costOfShares, which is to be inserted into the table ShareVales (SQL Server 2005). I am using CF8.
SQL
table:-ShareVales; field:-costOfShares; DataType:-float
ColdFusion (form page)
<li>
<cfinput size="8" maxlength="20" name="costOfShares"
id="costOfShares" value="#share.GetcostOfShares()#">
</li>
Share.cfc:-
<cfcomponent>
<cfscript> Variables.CostOfShare </cfscript>
<cffunction name="GetCostOfShare" returntype="numeric" access="public" output="false">
<cfscript> variables.CostOfShare; </cfscript>
</cffunction>
<cffunction name="SetCostOfShare" retuntype="void" access="public" output="false">
<cfargument name="costOfShare" type="string" required="true">
<cfscript> variables. costOfShare = arguments. costOfShare; </cfscript>
</cffunction>
</cfcomponent>
ColdFusion (query page)
<cffunction>
<cfargumnet>
<cfquery …>
INSERT INTO ShareVales(shareUnitId, costOfShares)
VALUES (
<cfqueryparam cfsqltype="cf_sql_integer"
value="#arguments.share.GetshareUnitId()#">,
<cfqueryparam cfsqltype="cf_sql_float"
value="#arguments.share.GetcostOfShares()#">);
</cfquery>
</cffunction>
When I use the following directly in the Query Editor:
INSERT into share(setCostOfShare)
values(Cast(replace('5,322,444',',','') as float))
it succeeds. The error is while using cfquery/cfqueryparam in the ColdFusion template.
So, how do insert the 45234 when the form field costOfShares contains a value with commas?
If they type a comma, strip it out first before trying to insert.
LSParseNumber("45,234", "French (standard)")
Or if "French (standard)" is already your system standard system default locale, just use:
LSParseNumber("45,234")
Or...
<cfset setLocale("French (standard)")>
<cfset value = LSParseNumber("45,234")>
They'll return 45.234 (if you want 45234 instead, use US locale, see doc!)
I'd suggest you to store costOfShares as a valid ColdFusion numeric value (aka, use '.' instead of
','), and only use LSNumberFormat() or LSLSCurrencyFormat() to display the value on the view. That way you don't even have to LSParse the number, unless the number is created by the user, and he uses ','.
presumably the datatype is a float or something. comma's are not valid characters in a float (unless for European locales). You probably want instead to get the value out of the DB with a comma (but not necessarily store it with one). That would probably mean using the COVERT function during a SELECT:
http://technet.microsoft.com/en-us/library/ms174450.aspx
Not sure if this will help or not, but just put the replace inside of cfqueryparam. That way it hands SQL Server the "already cleaned up version".
CAST(<cfqueryparam cfsqltype="cf_sql_float"
value="#REPLACE(arguments.share.GetcostOfShares()',',','')#"> AS FLOAT)
Or, have CF run a replace on the variable and clean it up before you even try the query.
Or, have CF run a replace on the variable and clean it up before you even pass it in as an argument.
I have the unfortunate task of cleaning up a bunch of old ColdFusion code. Queries are all over the place, I am working on moving them all to common CFCs for easier maintenance.
I am running into a problem because cfquery is automatically converting the single quotes to double-single-quotes. How can I override that behavior?
More specific information is below.
So here is the query I started with:
<cfquery name="getObjectInfo" datasource="#BaseDS#">
SELECT groupName AS lastname, '[Group]' AS firstname
FROM groups
WHERE groups.group_id = #objectreference_id#
</cfquery>
The weird thing here is that a literal is being "selected", because of the way we want it displayed (again, I didn't write this, I'm just trying to clean it up a little). So in the common function, there is an optional parameter for the select clause:
<cffunction name="fSelGroup" access="public" returntype="query"
hint="Returns query selecting given group.">
<cfargument name="intGroupID" type="numeric" required="true"
hint="ID of group to be returned." />
<cfargument name="strSelectAttributes" type="string" required="false"
hint="Attributes to be selected in query"
default="*" />
<cfquery name="getObjectInfo" datasource="#Application.DataSource#">
SELECT #Arguments.strSelectAttributes#
FROM Groups
WHERE Group_ID = #Arguments.intGroupID#
</cfquery>
<cfreturn getObjectInfo />
</cffunction>
Here is the problem: When I pass in "GroupName AS LastName, '[Group]' AS FirstName" for the strSelectAttributes parameter, the query that is sent to the database is:
SELECT GroupName AS LastName, ''[Group]'' AS FirstName
FROM Groups
WHERE Group_ID = 4
You see, my quotes got "sanitized" into an invalid query.
ColdFusion does not escape all single quotes, but only those that arrive in the query through variable interpolation. This is the offender:
SELECT #Arguments.strSelectAttributes#
This is usually a helpful thing and a small line of defense against SQL injection attacks. So rule number one is (here and everywhere else): Don't build your SQL string from variables.
If you positively have to use variables to build an SQL string, despite all the possible negative effects, use the PreserveSingleQuotes() function:
SELECT #PreserveSingleQuotes(Arguments.strSelectAttributes)#
This function stops ColdFusion from auto-escaping the single quotes.
And any other function call does the same thing, by the way. Try:
SELECT #LCase(Arguments.strSelectAttributes)#
which means that PreserveSingleQuotes() is really just a no-op that turns a string into a function result, preventing the automatic variable interpolation routine from happening.
Put a call to preserveSingleQuotes() around your variable. It's made specifically for writing dynamic SQL. Also, you really, really should use cfqueryparam for your values, and I hope you're sanitizing your input somehow so that arguments.strSelectAttributes can't contain something like ';drop table groups; in it.
<cfquery name="getObjectInfo" datasource="#Application.DataSource#">
SELECT #preserveSingleQuotes(Arguments.strSelectAttributes)#
FROM Groups
WHERE Group_ID = <cfqueryparam value="#Arguments.intGroupID#" cfsqltype="cf_sql_integer"/>
</cfquery>
If you really wanting to clean up the code step two is converting that spaghetti into stored procedures.