Check form submission against data in database? - coldfusion

We have a registration system that we're using where people fill out a form, and their info is put into our SQL database. However, we don't have a system in place to check for duplicate registrations, and I'm hoping to get some guidance on how to check maybe name or email address and set an error.
Here's our error setting code (one example, we have several checks):
<cfif not len(trim(form.last_name)) or form.last_name eq "Last Name">
<cfset errors = errors & "<li>You must include your complete last name.</li>">
</cfif>
If no errors are found, here is the query code to insert the data into the database:
<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#,
<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#">,
#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>
There's no "unique" identifier tied to a specific individual, so I'm thinking the best way is to prevent registrations that match someone with an identical first/last name or even just the email address. Any ideas on how to implement such a function using the above system would be helpful.

This is simplified but.. you get the idea.
<cfquery name="RegistrantEmailExists" datasource="#application.Datasource#" dbtype="odbc">
SELECT COUNT(email) as EmailExists FROM Schedule_Registrations WHERE email = <cfqueryparam value="#form.email#" cfsqltype="cf_sql_varchar" >
</cfquery>
<cfif RegistrantEmailExists.EmailExists gt 0>
<cfset errors = errors & "<li>That Email Address already exists.</li>">
</cfif>

You could also set the email column in the database as a primary key, which would definitely prevent duplicate registrations. You would of course have to gracefully handle the duplicate primary key which would be thrown from the DB!

Placing a unique key on the mail-column would be the easier way than changing the primary key. But you've also to handle the error thrown by the db

<cfquery name="checkdup" datasource="whatever">
Select 1 from Schedule_Registrations where email=#form.email#
</cfquery>
<cfif #checkdup.recordcount# is 0>
<cfquery name="doyourquery" datasource="whatever">
insert into Schedule_Registrations
(email,etc1,etc2) values ('#form.email#','#etc1#','#etc2#')
</cfquery>
Thanks for registering
<cfelse>
You have already registered an account
</cfif>
And yes, all the cfqueryparam stuff you'd need would go in there. This is just the basics of it.
Good Luck :)
WHeis

Related

how can I check if a record already in database before submitting form in ColdFusion applications

<cfquery datasource = "myDb" name = "compare">
select *
from users
where cnic = #form.cnic#
</cfquery>
<cfif compare.cnic eq form.cnic>
<p> *CNIC already Exists </p>
</cfif>
I think you're misstating the problem. It should be more like,
"How can I show a form to add a record I know is not in the database?"
Please clarify if that is not the case.
Based on your code, I assume there's been a form submission from another page already. You're running a query to see if there is a record in the users table where cnic = #form.cnic#. If there was no previous form submission, then form.cnic wouldn't exist.
<cfquery datasource="myDb" name="compare">
select *
from users
where
cnic = #form.cnic#
</cfquery>
So when this page loads, you've done your "check if a record is already in the database" with the query named compare. Now all you need to do is check if there are 0 records in the query.
<cfif compare.recordcount EQ 0>
<!--- Display form here. ---->
</cfif>
If the query returns any records, then there is at least one record in the database, so no need to show the form or allow it to be submitted.
You can use bellow code in Jquery ajax calling
<cfquery datasource = "myDb" name = "compare">
select *
from users
where cnic = #form.cnic#
</cfquery>
<cfif compare.recordcount GT 0>
<p> *CNIC already Exists </p>
</cfif>
Depending on your database, too, there are other options. MySQL has some features for INSERT ON DUPLICATE KEY UPDATE (https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html)
In MSSQL you can do:
IF NOT EXISTS (SELECT 1 FROM [users] u WITH (NOLOCK) WHERE cnic = <cfqueryparam cfsqltype="CF_SQL_VARCHAR" value="#form.cnic#")
INSERT INTO [users].....
(My cfsqltype syntax might not be 100% correct, but always use . Always.
Those might give you some other ways to handle your scenario.

Processing Incoming Mail from Mailgun with Coldfusion

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.

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>

CF (If..headerlocation)?

I am trying to make a CF code that will select the row "welcome" from the table
"users" where username = #session.username#.
If "welcome" = 1 then i want it to direct the user to /me/index.cfm
I am new at CF, how would this be possible.
Firstly you need to do a DB query by the sounds of it:
<cfquery name="getWelcome" datasource="yourDSN">
SELECT welcome
FROM users
WHERE username = <cfqueryparam value="#session.username#" cfsqltype="CF_SQL_VARCHAR">
</cfquery>
Then you need to check the value from the query, and also taking into account the fact that the query might not find anything at all.
<cfif NOT getWelcome.recordcount>
<!--- do something, maybe redirect to the login page --->
</cfif>
<cfif getWelcome.welcome EQ 1>
<cflocation url="/me/index.cfm">
</cfif>
The most important thing here is the use of cfqueryparam to prevent SQL injection.
You can write like :
<cfif welcome EQ 1>
<cflocation url="/me/index.cfm">
</cfif>

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