cfqueryparam pass in list from input checkbox - coldfusion

I have a input checkbox field where user can select multiple checkboxes in a form, and depending on what they select, it will create a string of id's like 10,14,35,47, and that will be submitted to the database. I can get this submitted if I just submit it directly like below:
user_job_type_id="#form.user_job_type_id#",
But, if I try and wrap that in a cfqueryparam, which I would rather do to make it more secure, I get an error, regardless of what I do. Whether I set it to a list true or false, varchar, integer, everything throws an error like cfqueryparam doesnt accept the list.
For example, below will not work
user_job_type_id=<cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.user_job_type_id#" list="Yes"/>,
What am I missing here?

As #SOS mentioned, you need to use an IN statement when checking against a list of values in parenthesis. In addition, since the values are all integers, make sure to specify the correct cfsqltype. This ensures the correct date type check for each element in the list.
Wrong:
user_job_type_id = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.user_job_type_id#" list="Yes"/>,
Better:
user_job_type_id IN (<cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.user_job_type_id#" list="Yes"/>),
Best:
user_job_type_id IN (<cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#form.user_job_type_id#" list="Yes"/>),

Related

Cfquery causing XSS and SQL Injection issues

I ran an application scan (IBM) recently and now I'm trying to fix the issues that came up. A good majority of my issues stem from a cfquery (see below). I'm trying to get it so that Stored XSS and SQL injections issues don't show up on my scans. Any help would be greatly appreciated, as this is my first time doing something of the sort.
Thanks!
<cfquery name="enter_question" datasource="#dsn#">
INSERT INTO xx_questions(q_id,
q_name,
q_narrative,
q_used,
q_type)
VALUES( #variables.new_q_id#,
'#form.q_name#',
'#form.q_narrative#',
'n',
#form.q_type#)
</cfquery>
Each query that contains user inputs should have cfqueryparam like so:
<cfquery name="enter_question" datasource="#dsn#">
INSERT INTO xx_questions(q_id,
q_name,
q_narrative,
q_used,
q_type)
VALUES(
<cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#variables.new_q_id#"/>,
<cfqueryparam cfsqltype="CF_SQL_CHAR" value="#form.q_name#"/>,
<cfqueryparam cfsqltype="CF_SQL_CHAR" value="#form.q_narrative#"/>,
<cfqueryparam cfsqltype="CF_SQL_CHAR" value="n"/>,
<cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#form.q_type#"/>)
</cfquery>
The cfsqltype will need to reflect the data type in the xx_questions table for the cooresponding column - but you get the idea.
Binding the variable to a type in this manner automatically protects you against SQLi injection. XSS injection is something else. That's when user input is output onto the page. If a user pushes something (say a script tag) into a column in the DB and then it is output onto the page you haven't really suffered from injection (they gave you a character column, you put in a character column, they did not change the nature of the query). But in a forum app or any other area where user input from one user is shown to another you have the potential for malicious code infections.
For that each of your character types needs to be vetted for malicious code. Using something like Foundeo as a Web application Firewall can do this. You can also protect your page at a server level using the CF admin or at an application level using the scriptprotect attribute of the cfapplication tag or props in the application.cfc.
You can also manually protect within your DB inserts using HTMLEditformat like so:
<cfqueryparam cfsqltype="CF_SQL_CHAR" value="#htmleditformat(form.q_narrative)#"/>,
... or you can check each user input against a list of known allowed inputs (if the data is predictable). These techniques should be part of your "best practice" list if possible. :)
You need to use <cfqueryparam>. Check the documentation at: https://wikidocs.adobe.com/wiki/display/coldfusionen/cfqueryparam
Try something like this (you should change the CFSQLType to match whatever your DB columns are):
<cfquery name="enter_question" datasource="#dsn#">
INSERT INTO xx_questions(q_id,
q_name,
q_narrative,
q_used,
q_type)
VALUES(
<cfqueryparam value="#variables.new_q_id#" CFSQLType="CF_SQL_INTEGER">,
<cfqueryparam value="#form.q_name#" CFSQLType="CF_SQL_VARCHAR">,
<cfqueryparam value="#form.q_narrative#" CFSQLType="CF_SQL_VARCHAR">,
<cfqueryparam value="n" CFSQLType="CF_SQL_CHAR">,
<cfqueryparam value="#form.q_type#" CFSQLType="CF_SQL_INTEGER">
)
</cfquery>

PreparedStatement.setNString(int,java.lang.String) error trying to use Query of Queries

I have a simple Query of Queries statement like this:
<cfquery name="rsProductTypeID" dbtype="query">
SELECT
ProductTypeID
FROM
rsProductTypes
WHERE
ProductType = <cfqueryparam value="Computers" cfsqltype="cf_sql_nvarchar"/>;
</cfquery>
All it is doing is asking for the primary key value (ProductTypeID) from the recordset rsProductType depending on which ProductType we are asking for.
For some reason the above query gives me this error:
PreparedStatement.setNString(int,java.lang.String)
But if I change the Query of Queries and remove the <cfqueryparam> part and replace it with normal text, then it works fine. Here is the working code:
<cfquery name="rsProductTypeID" dbtype="query">
SELECT
ProductTypeID
FROM
rsProductTypes
WHERE
ProductType = 'Computers';
</cfquery>
I can't tell what the difference is between the code that is causing it to fail when using <cfqueryparam> and not.
I think I figured it out... when ColdFusion returns a recordset, it doesn't maintain the original datatype from the database. In my database ProductType is defined as nvarchar(50) but ColdFusion returns it as varchar format. So the cfsqltype attribute was causing the error. I changed the cfsqltype attribute to cf_sql_varchar and it works fine. Very annoying but what can you do.
I posted it as a self-answer in case anyone else gets this error. Not sure if that's against the rules or not.
cf_sql_nvarchar is not a valid value for the cfsqltype attribute of cfqueryparam
Docs: https://wikidocs.adobe.com/wiki/display/coldfusionen/cfqueryparam

CFDump of query column does not display all values

The dumping results for the following QoQ are perfectly fine:
<cfquery datasource = "XX.XX.X.XX" name="master2">
SELECT DATE(Timedetail) as FIRSTCONN
, count(Timedetail) as FIRSTOccurances
, EVENTS
FROM MyDatabase
WHERE EVENTS = "FIRST" GROUP BY FIRSTCONN
<!--- LIMIT 0,10 --->;
</cfquery>
<cfdump var="#master2#">
<cfquery dbtype="query" name="detail2">
SELECT *
FROM master2
WHERE FIRSTCONN >= <cfqueryparam value="#startdate#" cfsqltype="cf_sql_date">
AND FIRSTCONN < <cfqueryparam value="#enddate#" cfsqltype="cf_sql_date">;
</cfquery>
Dumping Result: <cfdump var="#detail2#"><cfabort>
However, when I try to use the following check on the QoQ:
Dumping Result: <cfdump var="#detail2.FIRSTCONN#"><cfabort>
I don't see the full list of FIRSTCONN values. Instead I just see one line:
Dumping Result: {ts '2013-06-29 00:00:00'}
Ideally I should see the list of all the FIRSTCONN in my browser, shouldn't I?
You are looking at the default behaviour of coldfusion. When you output or dump queryname.fieldname, and don't specify a row number, you get the value from the first row. If you want to see all the rows, your choices are:
Look at the value list
Output/dump the entire query
Do another q of q for just that column and cfdump it.
Use cfoutput with a query attribute and just output that field
If you are looking to produce the same structured output that cfdump produces when dumping a query, I have two suggestions:
My First Inclination:
<cfdump var="#ListToArray(ValueList(queryName.columnName))#" />
That one is obviously a, very, minor continuation on Dan's suggestion.
The second is available for CF 8+ and it is
Exactly What You Wanted:
<cfdump var="#queryName#" show="columnName"/>
You may specify either columns to display in the output via the show attributes or you can hide specific columns by assigning a value to the hide attribute.
CFAbort in CF Docs
Granted, this post is almost 18 months old but maybe this will help someone that stumbles onto this page.
This is a little off topic, but I'd like to point out that in my instance of CF2016 the cfdump function suppresses the output of columns (and makes them appear empty) that have lots of text in them (or have the option to have lots of text). I'm not sure if it's the nVarChar(max) setting of the table field or what, but in order to see the content of these big fields, I actually have to make a separate query that selects only this one field, and use a separate cfdump in order to see its contents. This is only for debugging purposes, but it will keep you from going crazy and rewriting your update and insert statements over and over (because they appear to not be working all the way)...

Avoiding Magic values

I have some code that only does updates
<cfif tags NEQ "skip">
<cfquery>
UPDATE myTable
SET tags = <cfqueryparam cfsqltype="CF_SQL_varchar" value="#arguments.tags#">
WHERE ID = <cfqueryparam cfsqltype="CF_SQL_INTEGER" value="#arguments.ID#">
</cfquery>
What would be a better approach than using "skip" as a magic value? Note that blank is a valid value.
It depends on where the data is coming from. Ideally, I'd set a variable to true or false and check that. I'm guessing that in your example tags is coming from a form and that 'skip' is the value in a for 'None of these'. You've probably got to use something as a magic value, but I'd favour using something like __SKIP_TAGS__ which is very clear.
You could also split up your page logic, so that you process the form submission first, checking for magic values and setting up a boolean for whether to insert data from #tags#, then use the boolean later on for your check. The overall logic would be the same, but better laid out.
You might want to consider adding a bit more context to your question, like where the data is coming from, so that others can give you better advice

form data into database: preventing SQL injection

It has recently been mentioned to be that our method of inserting data into our SQL database via form submission is subject to SQL injection attacks, and want some advice to harden our security.
Here's the code that inserts form data into the DB:
<cfquery name="InsRegistrant" datasource="#application.Datasource#" dbtype="odbc">
INSERT INTO Schedule_Registrations(
schedule_id,
first_name,
last_name,
phone_number,
email,
guest,
list_type,
datetime_registered
)
VALUES(
#url.schedule_id#,
'#FORM.first_name#',
'#FORM.last_name#',
'#CleanPhoneNumber#',
'#FORM.email#',
#attendee.guest#,
<!--- Values for list types
0 = NEVER USE Will cause many many problems
1 = Main List
2 = Waiting List --->
#attendee.list_type#,
#createodbcdatetime(now())#
)
</cfquery>
CleanPhoneNumber is set this way:
<cfset CleanPhoneNumber = REReplace(form.phone_number, "[^0-9]", "", "ALL") />
I've been told to use, for instance,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#form.phone_number#" />
but I'm not sure what to replace and where. When I replace the values with such I get an error.
Any direction would be helpful..
You should wrap all form and url variables in cfqueryparam
Your query would look like this:
<cfquery name="InsRegistrant" datasource="#application.Datasource#" dbtype="odbc">
INSERT INTO Schedule_Registrations(
schedule_id,
first_name,
last_name,
phone_number,
email,
guest,
list_type,
datetime_registered
)
VALUES(
<cfqueryparam cfsqltype="cf_sql_integer" value="#url.schedule_id#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#FORM.first_name#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#FORM.last_name#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#CleanPhoneNumber#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#FORM.email#">,
<cfqueryparam cfsqltype="cf_sql_integer" value="#attendee.guest#">,
<!--- Values for list types
0 = NEVER USE Will cause many many problems
1 = Main List
2 = Waiting List --->
<cfqueryparam cfsqltype="cf_sql_integer" value="#attendee.list_type#">,
#createodbcdatetime(now())#
)
</cfquery>
I'm not sure I got all the data types correct, see the full documentation of cfqueryparam for all the data types.
There are several good practices you can do.
For the insert code you have provided one of the things you can do is explicitly check the input of the Form Fields before inserting the data.Check for things like spaces and "'". You also want to ensure that the user does not see your error messages from bad data entered. This is useful to somebody wanting to know your table structure.
Otherwise place the insert in a stored procedure and validate the input parameters before calling the stored procedure for the insert or update.
Here is a good list of things you can do to prevent SQL injection attacks. It is related to asp.net but the concepts still apply no matter what language you are using.
How To: Protect From Injection Attacks in ASP.NET