I want to add an "anti-robot" question to the CreateUserWizard as a more accessible alternative to a Captcha control. I'm fairly new to asp and finding that I'm a bit stuck in a WinForms mindset. However, I have come up with something that appears to work.
Markup:
<asp:CreateUserWizard ID="CreateUserWizard1" runat="server">
.
.
<tr>
<td align="right">
<asp:Label ID="AntiRobotQuestion" runat="server" AssociatedControlID="AntiRobotAnswer">
Question:
</asp:Label>
</td>
<td>
<asp:TextBox ID="AntiRobotAnswer" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="AntiRobotAnswerRequired" runat="server" ControlToValidate="AntiRobotAnswer" ErrorMessage="Answer is required." ToolTip="Answer is required." ValidationGroup="CreateUserWizard1">
</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td align="center" colspan="2" style="color:Red;">
<asp:Literal ID="CustomErrorMessage" runat="server" Visible="False" EnableViewState="False"></asp:Literal>
</td>
</tr>
.
.
</asp:CreateUserWizard>
Code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
//Set up the Anti-Robot Question and Answer
Label robotQuestion = (Label)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("AntiRobotQuestion");
//Simulate randomly selecting a question and answer from a database table...
robotQuestion.Text = "What is the capital of France";
Session["AntiRobotAnswer"] = "Paris";
}
}
protected void CreateUserWizard1_CreatingUser(object sender, LoginCancelEventArgs e)
{
//Check the anti-robot Q & A
TextBox robotAnswer = (TextBox)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("AntiRobotAnswer");
if (robotAnswer.Text != (string)Session["AntiRobotAnswer"])
{
Literal errorMessage = (Literal)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("CustomErrorMessage");
errorMessage.Text = "Wrong answer! Are you a robot?";
errorMessage.Visible = true;
e.Cancel = true;
}
}
Is this an acceptable way to code this? Two things in particular look a bit "untidy" to me:
- The use of FindControl to pull out references to controls in the markup.
- Storing the expected answer in a session variable. (How secure is it?)
EDIT (2012-01-23) Some valid design alternatives have been given. However, I have a valid reason to use this question and answer technique (possibly in addition to the honeypot idea). For example, a question relevant to the subject of a forum can help to prevent human spammers as well as bots. The question is: is the code outlined above an acceptable way to do this? Coming from a WinForms background, it looks a bit clunky to me - but maybe that's what asp is supposed to look like.
As I say, I do not like the idea of you to ask for Paris.
The simplest way is to use a non visible field and see if a bot fill it with data, the honeypot idea http://haacked.com/archive/2007/09/11/honeypot-captcha.aspx
also you can use the NoBot from asp.net toolkit http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/NoBot/NoBot.aspx
There are many other ideas on this SO article Practical non-image based CAPTCHA approaches?