Home > Apex, force.com Sites, Visualforce > Simple Visualforce Captcha

Simple Visualforce Captcha

July 16th, 2009

With Force.com sites now in GA it is possible to create public facing web forms and save directly to your salesforce.com database. You can do point of entry validation, auto fill fields based on the user, and all sort of other awesomeness. One problem with public facing forms is they are prone to spam, lots of spam. The best approach is to prevent the spam from even being submitted in the first place. This is usually done with some sort of CAPTCHA validation.

Ron Hess put together a great little article here on how you can use reCAPTCHA. It works great but (there is always a but) it requires setting up a web service callout, using javascript, and isn’t the the most straight forward CAPTCHA to setup. I am all about 100% salesforce.com. Javascript libraries and external services are great but if I can do the same thing with 100% Apex and Visualforce I’m all for that.

With this mindset I set out to create a CAPTCHA utility built 100% on the force.com platform. I think my results where pretty darn successful. It isn’t super fancy but I think it will get the job done……but then again it hasn’t exactly been tested against spam bots. Oh well, it’s still cool.

You can check out a working example here: http://tehnrd-developer-edition.na7.force.com/captcha

And here is the code, first the page:

<apex:page controller="captcha" >
 
    Enter only the <strong>black</strong> characters.
    <apex:outputPanel styleClass="container" layout="block" id="code">
        <apex:outputText value="{!char1}" styleClass="blackChar"/>
        <apex:outputText value="{!char2}" styleClass="redChar"/>
        <apex:outputText value="{!char3}" styleClass="blackChar"/>
        <apex:outputText value="{!char4}" styleClass="redChar"/>
        <apex:outputText value="{!char5}" styleClass="blackChar"/>
        <apex:outputText value="{!char6}" styleClass="redChar"/>
    </apex:outputPanel>
 
    <apex:form >
        <apex:inputText value="{!input}"/>
        <apex:commandButton action="{!validate}" value="Validate" rerender="result"/>
        <apex:commandButton value="Reset" rerender="code"/>
    </apex:form>
 
    <apex:outputPanel id="result">
        {!result}
    </apex:outputPanel>
 
    <style>
        .redChar{
            color: #C30000;
            font-size: 24px;
            padding:5px;
        }
        .blackChar{
            color: black;
            font-weight: bold;
            font-size: 24px;
            padding:5px;
        }
        .container{
            background-color: #E8E8E8;
            border-style: solid;
            border-width:1px;
            width: 150px;
            text-align: center;
        }
    </style>
</apex:page>

And next the controller:

public class captcha {
 
    List<String> characters;
    public String input {get; set;}
    public String result {get; set;}
    String char1;
    String char3;
    String char5;
 
    //In our contructor we will populate a list of strings with numbers and letters
    public captcha(){
        characters = new List<String>{'a','b','c','d','e','f','g','h',
            'i','j','k','l','m','n','o','p','q','r','s','t','u','v','w',
            'x','y','z','1','2','3','4','5','6','7','8','9','0'
        };
    }
 
    //This methods simply returns a random number between 0 and the size of the character list
    public Integer randomNumber(){
        Integer random = Math.Round(Math.Random() * characters.Size());
        if(random == characters.size()){
            random--;
        }
        return random;
    }
 
    /*Here we have 6 get methods that return 6 random characters to the page.
    For chars 1,3, and 5 (the black characters) we are saving the the values so 
    that we can compare them with the user's input */
    public String getChar1(){
        char1 = characters[randomNumber()];
        return char1;
    }
    public String getChar2(){
        return characters[randomNumber()];
    }
    public String getChar3(){
        char3 = characters[randomNumber()];
        return char3;
    }
    public String getChar4(){
        return characters[randomNumber()];
    }
    public String getChar5(){
        char5 = characters[randomNumber()];
        return char5;
    }
    public String getChar6(){
        return characters[randomNumber()];
    }
 
    /*In the validate method we make sure that the 3 characters entered equal the three black characters: char1, char3, char5*/
    public void validate(){
        if(input.length() == 3 && input.subString(0,1) == char1 && input.subString(1,2) == char3 && input.subString(2,3) == char5){
            result = 'Whoohoo! You got it right.';
        }else{
            result = 'Come on...the letters aren\'t even disfigured.'; 
        }
    }
}

The next logical step would be turning this into a component but this should give you a pretty good start.

  1. amir hafeez
    October 20th, 2009 at 08:54 | #1

    Really cool is that how u get a random number from apex? math.random * range

  2. October 20th, 2009 at 09:07 | #2

    Yup, Math.Random() returns a random value greater than 0.0 and less than 1.0 which you then multiply by your range. You can then round it to get the whole number.

  3. March 29th, 2010 at 11:56 | #3

    Hmm…I think you’d want the CAPTCHA to show up in an image, not as selectable text. It’s pretty easy to create a spam-bot that can cut-and-paste…

    Cool idea, though! :)

  4. March 29th, 2010 at 12:08 | #4

    True, but to my credit it is labeled as a “Simple” CAPTCHA. I don’t think a spam-bot can copy and paste in a traditional sense. It would have to crawl the DOM and identify only the black characters to paste, styleClass=”blackChar”. To add more security you could create random class names and pass these to the style names and styleClass attributes. You could also wrap the letters in several layers of DIVs and SPANs and then render these randomly to make DOM traversing even more difficult.

    No CAPTCHA is perfect but considering the simplicity of this one, it works pretty well.

  5. March 29th, 2010 at 12:41 | #5

    Bookedmarked! Will definitely use in the future. Thanks!

  6. March 30th, 2010 at 10:29 | #6

    I love the idea, and it’s definitely much simpler. However, I think Rob has a very valid point. It would be pretty easy to upload a handful of images as static resources and then just randomly choose one to show up. You could use a case function based on the image name to match the captcha image with the correct text. Just make sure the image name doesn’t include the text since that could be read in the HTML also.

  7. Johan Liljegren
    March 30th, 2010 at 12:20 | #7

    You rock, Jason. Keep up the quality code and demos – I’m learning a lot!

  8. DK
    March 23rd, 2011 at 13:19 | #8

    Can i use this in the web to lead form …