This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Coldfusion adding extra quotes when constructing database queries in strings
All,
I am trying to use a getter to reference a bean during an insert. CF is not escaping the single quote properly in the value in 'form.title' and therefore I am receiving a malformed sql error.
Any ideas?
Here's the code.
<cfscript>
form.title = "page's are awesome";
page = new model.page.page(argumentCollection = form);
<cfquery name="test" datasource="ksurvey">
insert into page(title)
values('#page.getTitle()#')
</cfquery>
If you're going to do it that way, you need preserveSingleQuotes()
INSERT INTO page( title )
VALUES ( '#preserveSingleQuotes( page.getTitle() )#' )
Of course, insert the standard caveat about how you should be using cfqueryparam to avoid SQL injection attacks.
INSERT INTO page( title )
VALUES ( <cfqueryparam value="#page.getTitle()#" cfsqltype="cf_sql_varchar" /> )
For reference:
http://cfquickdocs.com/cf9/#preservesinglequotes
http://cfquickdocs.com/cf9/#cfqueryparam
I wouldn't insert any value into a database without using cfqueryparam, its not safe! Not only that but cfqueryparam will handle all the escaping for you.
<cfquery name="test" datasource="ksurvey">
insert into
page(title)
values(<cfqueryparam value="#page.getTitle()#" cfsqltype="cf_sql_varchar">);
</cfquery>
Related
I've just started using Mailgun for 2-way emails within a web app I'm developing for in-house use. I have a route set up to forward messages to a URL on my server - which is working fine.
However, the code at my end to process these messages is throwing errors. Malign sends the data as a http post, which I can then reference with a form variable. Initially I was getting 'not defined' errors on some fields (those with hyphens in the field names), however that now appears to be resolved. The code is now stumbling on the CFQUERY insert, with the error stating I have an error in the SQL syntax - but I can't see anything wrong with it!
This is the code I have for the page mailgun sends the post to;
<cfset thebody = form["body-plain"]>
<cfset thesender = form["sender"]>
<cfset therecipient = form["sender"]>
<cfset thesubject = form["subject"]>
<cfquery name="addmail">
INSERT INTO mailmessages(from,sender,recipient,subject,body,msgdate)
VALUES('#thesender#','#thesender#','#therecipient#','#thesubject#','#thebody#',#CreateODBCDateTime(Now())#)
</cfquery>
The error message states;
Error Executing Database Query. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from,sender,recipient,subject,body,msgdate) VALUES('lee#mydomain.com','l' at line 1
A cfdump of the form can be seen here (this is sent to be via cfmail in a cfcatch statement - the only way I'm able to see any errors);
The from column name is a reserved word, so this is what mySQL is complaining about.
If you escape the column name, it should fix this.
Along with cfqueryparam your code should be something like:
<cfset thebody = form["body-plain"]>
<cfset thesender = form["sender"]>
<cfset therecipient = form["sender"]>
<cfset thesubject = form["subject"]>
<cfquery name="addmail">
INSERT INTO mailmessages (
"from",
sender,
recipient,
subject,
body,
msgdate
)
VALUES (
<cfqueryparam value="#thesender#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#thesender#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#therecipient#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#thesubject#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#thebody#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#CreateODBCDateTime(Now())#" cfsqltype="cf_sql_timestamp">
)
</cfquery>
As the error message suggests, there is a syntax error in the insert query.
Seems like you are missing single quotes (') around the date value you are passing. It should be written like this:
<cfquery name="addmail">
INSERT INTO mailmessages(from,sender,recipient,subject,body,msgdate)
VALUES('#thesender#','#thesender#','#therecipient#','#thesubject#','#thebody#','#CreateODBCDateTime(Now())#')
</cfquery>
To get rid of such syntax errors and prevent SQL injection always use cfqueryparams like this:
<cfquery name="addmail">
INSERT INTO mailmessages (from,sender,recipient,subject,body,msgdate)
VALUES (
<cfqueryparam value="#thesender#" cfsqltype="CF_SQL_VARCHAR">,
<cfqueryparam value="#thesender#" cfsqltype="CF_SQL_VARCHAR">,
<cfqueryparam value="#therecipient#" cfsqltype="CF_SQL_VARCHAR">,
<cfqueryparam value="#thesubject#" cfsqltype="CF_SQL_VARCHAR">,
<cfqueryparam value="#thebody#" cfsqltype="CF_SQL_VARCHAR">,
<cfqueryparam value="#CreateODBCDateTime(Now())#" cfsqltype="CF_SQL_TIMESTAMP">
)
</cfquery>
Instead of CF_SQL_TIMESTAMP you can also use CF_SQL_DATE as per your DB or data type you have specified for the column.
I can't select Jedihomer Townend's comment above as the answer, but he was correct to point out that my fieldnames contained reserved words, and that was causing the problem. Changing those fixed it.
I have the block of code below which runs a query and checks for an existing record and runs a second insert query if no record is found.
<cffunction name="EndRequestFunc" access="public" returnType="string">
<!---Queries Table To Get Requested Record--->
<cfquery name="qryGetPageRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
SELECT pageName
FROM tblCFMPageRequest
WHERE pageName = '#CGI.HTTP_REFERER#' AND scriptName =
'#CGI.SCRIPT_NAME#'
</cfquery>
<!---Conditional Check for record count equal to 0--->
<cfif qryGetPageRecord.recordCount eq 0>
<!---If record count equal to 0, recordset query executed--->
<cfquery name="setNewRecord" datasource="First_Main_Dev"
dbname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES ('#CGI.HTTP_REFERER#', '#CGI.SCRIPT_NAME#')
</cfquery>
</cfif>
</cffunction>
What I need to do is strip the values of the two CGI variables of all formatting so that a value like this "example.com/portal/mypage.cfm" will be stripped of http and everything else down everything to just mypage.cfm before its inserted by the query. Any guidance would be appreciated.
Update: Thank to the advice given, I was able to eliminate the http://example.com/ portion of the URL using the ListLast function.
I was short sighted in not remembering my urls have characters that need to be eliminated after the "cfm" point. Here is one of my actual results from ListLast: client_modify.cfm?uid=248&al=1&a_trigger=1.
I've tried using some other List functions in Coldfusion to no avail as of yet. Any advice on how to eliminate the bold portion of:
client_modify.cfm ?uid=248&al=1&a_trigger=1 so I'm just left with a clean client_modify.cfm
Use ListLast() function with / as a delimiter. Also, always try to use cfqueryparam to put values in queries. Like this.
<cfquery name="setNewRecord" datasource="First_Main_Dev" bname="First_Services_Dev">
INSERT INTO tblCFMPageRequest
VALUES (<cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.HTTP_REFERER,'/')#">, <cfqueryparam cfsqltype="cf_sql_varchar" value="#ListLast(CGI.SCRIPT_NAME,'/')#">)
</cfquery>
CGI variables shouldn't have any "formatting", so your question is a bit confusing.
If you're just looking to get the filename at the end of the string, you can use the list functions.
fileIwant = ListLast(CGI.SCRIPT_NAME,"/");
If CGI.SCRIPT_NAME is /wwwroot/example/index.cfm, fileIwant will result in index.cfm.
Have a care with the referrer, as it may not be defined and parsing it out will throw an error.
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>
I am trying to retrieve CLOB data from our Oracle database. the code is the following:
<cfstoredproc datasource="#request.site.datasource#" procedure="GETPAGESWITHMETADATA" result="myResults">
<cfprocparam cfsqltype="CF_SQL_VARCHAR" type="in" value="News">
<cfprocparam cfsqltype="CF_SQL_VARCHAR" type="in" value="News Pages">
<cfprocparam cfsqltype="CF_SQL_CLOB" type="out" variable="XML">
<cfprocresult name="rs1">
</cfstoredproc>
<cfdump var="#myResults#">
<cfoutput>#XML#</cfoutput>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
Basically, the output of the stored procedure is:
select dbms_xmlquery.getxml(queryCtx) INTO XML from dual;
I checked the data sources on the server and the "Enable long text retrieval (CLOB)." option is checked for every data source.
Surprisingly, instead of getting the XML result on screen, I get a very short string:
[C#74897f5e
It looks like a handle id instead of the content itself.
How can I retrieve the complete content of the XML?
For reference, the data source is using macromedia drivers with TNS name:
Driver class: macromedia.jdbc.MacromediaDriver
As #MarkAKruger suggested, returning a table from the procedure solved the issue.
The following PL/SQL code did the trick:
create or replace
PACKAGE PCK_Commonspot
AS
type t_clob IS record (metadata CLOB) ;
type t_clob_tab IS TABLE OF t_clob;
FUNCTION GetPagesWithMetadataAsRS(FormName varchar2, CategoryName varchar2)
RETURN t_clob_tab pipelined;
END PCK_Commonspot;
The package body contains the following code:
FUNCTION GetPagesWithMetadataAsRS(FormName varchar2, CategoryName varchar2)
RETURN t_clob_tab pipelined
IS
r t_clob;
BEGIN
GETPAGESWITHMETADATA(FormName, CategoryName, r.metadata) ;
pipe row(r) ;
RETURN;
END;
The function GETPAGESWITHMETADATA is the one returning a CLOB into r.metadata
Here, the trick is around returning a piped table.
It becomes super nice on the ColdFusion side because the call is really simple:
<cfquery name="Test" datasource="myDS" maxrows="1">
SELECT * FROM TABLE(PCK_Commonspot.GetPagesWithMetadataAsRS('abc','def'))
</cfquery>
<cfset XML = Xmlparse(Test.Metadata)>
Thanks Mark!
Check your datasource settings in the CF Administrator. Under the advanced settings, there are check boxes to allow BLOB and CLOB data to be returned. If they are unchecked you potentially could get truncated data returned in your queries
Even though Jaepetto has already answered his question, I thought I'd contribute another answer for posterity.
I was having similar problems returning CLOB data into CF8 from Oracle 11g. The original solution (that wasn't working) was roughly:
<cfquery name="GetDoc" DATASOURCE=myDS>
SELECT CLOBDATA FROM FILES WHERE FILES.FILEID = #FileID#
</cfquery>
This query would complete successfully, but GetDoc.CLOBDATA would always be an empty string. It turned out that retrieving CLOB data using cfquery would always do this, but if I wrapped it up in a stored proc then it worked. I assume this is some quirk of the JDBC drivers we're using.
Anyway, the CF guts of my solution was as follows. Note the use of CF_SQL_LONGVARCHAR instead of CF_SQL_CLOB - using CF_SQL_CLOB gave me the weird handle ID value that Jaepetto was seeing.
<cfstoredproc PROCEDURE="GETCLOB" DATASOURCE=myDS >
<CFPROCPARAM TYPE="IN" CFSQLTYPE="CF_SQL_INTEGER" DBVARNAME="pFileID" value="#fileID#"/>
<CFPROCPARAM TYPE="OUT" CFSQLTYPE="CF_SQL_LONGVARCHAR" DBVARNAME="pClob" VARIABLE="vClob" />
</cfstoredproc>
<!--- Dump the clob to the local filesystem --->
<cfscript>
fstream = CreateObject("java", "java.io.FileOutputStream").init(filepath, JavaCast("boolean","true"));
outStream = CreateObject("java", "java.io.BufferedOutputStream").init(fstream);
outStream.write(#toBinary(vClob)#);
outStream.flush();
outStream.close();
</cfscript>
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