Preventing form spam with ColdFusion serverside validation, rather than CAPTCHA

Web developers all over the world are constantly fighting form spam; there are lots of techniques, some good, some bad; most of them unfortunately involve looking at a graphic of some sort and then entering a series of numbers or digits to proceed with the form submission (a CAPTCHA).

This is obviously completely useless if you’re someone who can’t see the screen, or are using an assisted technology to help browse the web.

What I outline here is a combination of methods for fighting form spam using serverside validation. My requirements are:

  • no javascript: the form must work with or without it.
  • must be as accessible as possible
  • must be as “useable” as possible
  • and obviously, must prevent automated submission as much as possible.
  • Throw errors and alert the user without making them reinsert all the data into the form.

In this example, I’m doing the following tests:

  • the “empty form field hidden by CSS” trick: this still seems to work a bit; create a form field called Referral code, and hide it with CSS display:none; The dumber spam bots tend to fill in all the form fields with junk.
  • Check it’s a valid email address
  • Check there are no URLs in the subject or name line: refers again to the bots filling in forms unintelligently
  • Check the form is less that 8 hours old, but older than 3 seconds: this should prevent a spam bot caching the form and then using the cached version to pump POST requests to your processing page; bots submit automatically, so will trigger the less than 3 seconds error. The time in the form is set by the server
  • Check the form is being submitted from the correct URL/Domain/IP address: again, an anti spam caching technique.

Part One: setting up params, and error checking code

<cfsilent>
<cfparam name=“form.name” default=“” type=“string”>
<cfparam name=“form.email” default=“” type=“string”>
<cfparam name=“form.subject” default=“” type=“string”>
<cfparam name=“form.message” default=“” type=“string”>
<cfparam name=“form.referral” default=“” type=“string”>
<cfparam name=“form.timeposted” default=“#Now()#” type=“date”>
<cfparam name=“showform” default=“true”>

<!—Add your domain name here—>
<cfparam name=“yourdomainname” default=“www.oxalto.co.uk”>

<!—Create Error Handling Struct—>
<cfset errorStruct=StructNew()>
<cfif isdefined(“form.submit”)>
  <!—Check Referrer—>
  <cfif cgi.SERVER_NAME NEQ yourdomainname>
    <cfset errorStruct.serverError=“Oh dear. It looks to me like you’re trying to send a POST request from a machine other than the authorized webserver.”>
  </cfif>
  <!—Check Time submitted vs Now()—>
    <cfif DateDiff(“s”, form.timeposted, now()) LTE 3>
    <cfset timetocomplete= DateDiff(“s”, form.timeposted, now())>
    <cfset errorStruct.timetocomplete=“This form seems to have been submitted a little too quickly (#timetocomplete# seconds). Try again and take your time..”>
  </cfif>

<!—Check Form isn’t too old—>
<cfif DateDiff(“d”, form.timeposted, now()) GTE 1>
  <cfset errorStruct.formage=“This form seems to be really old: you may have submitted it from a cached version.”>
</cfif>

<!—Check Valid Email—>
<cfif NOT isValid(“email”, form.email)>
<cfset errorStruct.email=“That doesn’t appear to be a valid email address, please check and try again.”>
</cfif>

<!—Check Referral field is empty—>
<cfif len(form.referral) GT 1>
<cfset errorStruct.reffield=“That does not appear to be a valid referral code: please only enter a code here if you have been given one by our administrator”>
</cfif>

<!—Check Subject—>
<cfif len(form.subject) LT 1>
<cfset errorStruct.subject=“You must enter a subject”>
</cfif>

<!—Check Name—>
<cfif len(form.name) LT 1>
<cfset errorStruct.name=“You must enter your name”>
</cfif>

<!—Check Message—>
<cfif len(form.message) LT 1>
<cfset errorStruct.Message=“You didn’t enter a message”>
</cfif>

<cfif StructisEmpty(ErrorStruct)>
<!—If all ok, send mail—>
<cfmail to=“you@yourdomainname.com“ from=“#form.email#” subject=“[foo] #form.subject#”>
#form.email#
—-
#form.name#
—-
#form.subject#
—-
#form.message#
</cfmail>

</cfif> 
</cfif>
</cfsilent>

Part Two: The output

<html>
<head>
<style>
<!—Some Sample CSS—>
.contact-form {width:450px;}
.contact-form input { display:block;}
.error {color: #FF0000;}
.success {color:#009933;}
label { background-color:#000000; display:block; color:#FFFFFF;}
</style>
</head>
<body>

<h1>Contact</h1>

<!—Notify of error or success—>
<cfif isdefined(“form.submit”)>
<cfif NOT StructisEmpty(errorStruct)>
<p class=“error”>Message sending failed: there are errors in this form, please review before re-submitting.</h3>
<cfif StructKeyExists(ErrorStruct, “serverError”)><cfoutput><p class=“error”>#ErrorStruct.ServerError#</p></cfoutput></cfif>
<cfif StructKeyExists(ErrorStruct, “TimeToComplete”)><cfoutput><p class=“error”>#ErrorStruct.TimeToComplete#</p></cfoutput></cfif>
<cfif StructKeyExists(ErrorStruct, “FormAge”)><cfoutput><p class=“error”>#ErrorStruct.FormAge#</p></cfoutput></cfif>
<cfset showform=true>
<cfelse>
<h3 class=“success”>Thank you, your message has been sent</h3>
<cfset showform=false>
</cfif>
</cfif>

<cfif showform>
<cfform method=“post” action=“#cgi.SCRIPT_NAME#” name=“contact-form” class=“contact-form”>
<fieldset>
<legend>Contact Form</legend>
<label for=“name” <cfif structkeyexists(errorStruct, “name”)>class=“error”</cfif>>Name</label>
<cfinput type=“text” name=“name” message=“Please enter your name” value=“#form.name#”>
<cfif structkeyexists(errorStruct, “name”)><cfoutput><p class=“error”>#ErrorStruct.name#</p></cfoutput></cfif>
<label for=“email” <cfif structkeyexists(errorStruct, “email”)>class=“error”</cfif>>Email Address</label>
<cfinput type=“text” name=“email” message=“You must enter a valid email address” value=“#form.email#”>
<cfif structkeyexists(errorStruct, “email”)><cfoutput><p class=“error”>#ErrorStruct.email#</p></cfoutput></cfif>
<div style=“display:none;”>
<label for=“referral” <cfif structkeyexists(errorStruct, “reffield”)>class=“error”</cfif>>Referral Code (optional)</label>
<cfinput type=“text” name=“referral” value=“#form.referral#”>
<cfif structkeyexists(errorStruct, “reffield”)><cfoutput><p class=“error”>#ErrorStruct.reffield#</p></cfoutput></cfif>
</div>
<label for=“subject” <cfif structkeyexists(errorStruct, “subject”)>class=“error”</cfif>>Subject</label>
<cfinput type=“text” name=“subject” message=“You need to add a subject” value=“#form.subject#”>
<cfif structkeyexists(errorStruct, “name”)><cfoutput><p class=“error”>#ErrorStruct.subject#</p></cfoutput></cfif>
</fieldset>
<fieldset>
<label for=“message” <cfif structkeyexists(errorStruct, “message”)>class=“error”</cfif>>Message</label>
<cftextarea name=“message” message=“You haven’t said anything in the message field” rows=“5″ cols=“35″><cfoutput>#form.message#</cfoutput></cftextarea>
<cfif structkeyexists(errorStruct, “name”)><cfoutput><p class=“error”>#ErrorStruct.message#</p></cfoutput></cfif>
<cfinput type=“hidden” value=“#now()#” readonly=“yes” name=“timeposted” class=“hide”>
<cfinput type=“submit” name=“submit” value=“submit” class=“submit”>
</fieldset>
</cfform>
</cfif>
</body>
</html>

Galleon 2 released

The ever tireless Ray Camden has released Galleon Forums V 2:

Rays Blog

Get it HERE

Using the Flickr API to retrieve a list of photosets

[Edit: 7 years later, flickr’s changed their API to SSL only, so you may have to change all http references to https]

[Edit: 9 years later, here’s some simpler code: https://gist.github.com/neokoenig/d98f678054df0f08df77cba98ed30876 ]

Lots of good work has been done on the Flickr API with ColdFusion already: specifically, CFlickr – see http://chris.m0nk3y.net/projects/CFlickr/.

However, for my uses, I didn’t need anything near as complicated: All I wanted to do was to pull a list of photosets, their titles, primary thumbnail and description.

Thankfully, this is quite easy due to the Flickr API.

Part One: Making the request to Flickr

I’m assuming you have an API code, and know your userID:


<!---Flickr Params-->




<!---url.reinit used to manually refresh-->


<!--- Do we have this value? -->


<!---Send my Request to Flickr: this will get an XML doc with all my public photosets-->
   
    
    
    
    
   

<!---parse the XML doc-->




<!---Is XML request returned properly?-->

   Failed


<!---Set the time this was done-->
   

<!---Parse/narrow down the info I need into an Array-->



Part Two: Output: I’ve got my XML data, and now just need to loop over the Array.

</pre>
<h2>Photos</h2>
<pre>
<!--XML last cached #application.FlickrXmlstarted#--></pre>
<div id="photoset" class="clear">
<!---Output primary image--> <img class="left" src="http://farm#photosets[i].XmlAttributes['farm']#.static.flickr.com/#photosets[i].XmlAttributes['server']#/#photosets[i].XmlAttributes['primary']#_#photosets[i].XmlAttributes['secret']#_s.jpg" /> <!---output title-->
<h4><a href="http://www.flickr.com/photos/#userid#/sets/#photosets[i].XmlAttributes['id']#/">#photosets[i].title.xmltext#</a></h4>

<!---If description exists, show--> #photosets[i].description.xmltext#</div>
<pre>



And that’s it: I’ve cached the XML data in the Application scope for speed, and I’m looping over the XML data object. If a description exists for the set, it’s output.