|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAntiAuto is a set of controls that can be used on an ASP.NET Web Form to prevent automatic registrations from 'bots. It was something mentioned in the Lounge fairly recently and I thought it would be a good example for ASP.NET's superior application architecture. Many sites require users to register before they're given full access. For example, Hotmail.com requires you to enter a few basic details to provide you with an email address. However, this type of service is open to abuse - the automatic generation of many email addresses to be used for sending spam by a piece of software that automatically completes the registration process generating random user names etc. To prevent this type of abuse many sites require users to enter a code that is displayed in a picture -- thus forcing the person to enter the registration details. The aim is to produce a set of ASP.NET control's that can be easily deployed, and will fit in around an existing registration procedure. Solution OverviewTo give an overview to the classes within the project, here's a quick UML class diagram.
The important classes being CodeImageThe purpose of this class is to produce the HTML on the web form that will
display the image. The image itself is generated by the CodeImageValidatorThis is a How they work togetherWhen a page is first loaded a random number is generated, this is then passed
as part of a query string to the Implementation DetailsCodeImage
<img src="DrawImage.aspx?code=12345"> The code for the entire class is as follows: public class CodeImage : Control
{
private string _key;
private int _digits;
public CodeImage()
{
_key = System.Configuration.ConfigurationSettings.AppSettings["EncryptionKey"];
_digits = Int32.Parse(System.Configuration.ConfigurationSettings.AppSettings["Digits"]);
}
public string Code
{
get
{
return (string)ViewState["SecretCode"];
}
set
{
ViewState["SecretCode"] = value;
}
}
protected override void Render(HtmlTextWriter output)
{
output.Write( String.Format("<img src=\"DrawImage.aspx?code={0}\">",
HttpUtility.UrlEncode(Code)));
}
protected override void OnLoad(System.EventArgs e)
{
if (!this.Page.IsPostBack)
{
StringBuilder sbCode = new StringBuilder(_digits,_digits);
Random R = new Random();
int i;
int MaxLimit = 9;
for(i = 0; i < _digits; i++)
{
sbCode.Append(R.Next(MaxLimit));
}
Code = Util.EncryptString(sbCode.ToString(),_key);
}
}
}
It's extremely simple code, loading a couple of configuration settings in the
Constructor. These are used across the various controls and pages, so using
the The Render method is overridden to write out the HTML code, the security code
to be displayed in the picture comes from the It's also important to note that the encrypted security code is The The CodeImageValidatorThis class is implemented in the Again, the code is relatively simple so here's the entire class implementation before the discussion: public class CodeImageValidator : BaseValidator
{
TextBox _codeTextBox;
string _codeImageId;
CodeImage _codeImageControl;
string _key;
public CodeImageValidator()
{
_key = System.Configuration.ConfigurationSettings.AppSettings["EncryptionKey"];
}
protected override bool ControlPropertiesValid()
{
// Should have a text box control to check
Control ctrl = FindControl(ControlToValidate);
Control imageControl = FindControl(_codeImageId);
if ( (null != ctrl) && (null != imageControl) )
{
if ((ctrl is System.Web.UI.WebControls.TextBox) &&
(imageControl is CodeImage))
{
_codeTextBox = (System.Web.UI.WebControls.TextBox) ctrl;
_codeImageControl = (CodeImage) imageControl;
return ( (null != _codeTextBox) && (null != _codeImageControl) );
}
else
return false;
}
else
return false;
}
public string CodeImageControl
{
get
{
return _codeImageId;
}
set
{
_codeImageId = value;
}
}
protected override bool EvaluateIsValid()
{
return (Util.DecryptString(_codeImageControl.Code,_key) ==
_codeTextBox.Text);
}
}
The The DrawImage.aspxThe DrawImage page is used to produce the JPEG stream to send to the browser
and uses the
<%@ Page Language="C#" ContentType="image/jpeg" %>
<script language="C#" runat="server">
void Page_Load (Object sender, EventArgs e)
{
// Draw the output
Etier.AntiAuto.PictureGenerator.OutputPicture( this,
HttpUtility.UrlDecode(Request.QueryString["code"]) );
}
</script>
First the The code to the public static void OutputPicture(System.Web.UI.Page page, string encryptedCode)
{
page.Response.Clear();
string key = System.Configuration.ConfigurationSettings.AppSettings["EncryptionKey"];
int digits = Int32.Parse(System.Configuration.ConfigurationSettings.AppSettings["Digits"]);
Bitmap codeBitmap = new Bitmap((digits*16)+20,26, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(codeBitmap);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(Color.Orange);
g.DrawString( Util.DecryptString(encryptedCode,key), new Font("Arial", 16,
FontStyle.Bold ), SystemBrushes.WindowText, new Point(10,2));
codeBitmap.Save( page.Response.OutputStream, ImageFormat.Jpeg);
g.Dispose();
codeBitmap.Dispose();
page.Response.End();
}
The code is based on Nick Parker's "Web
Graphics On The Fly in ASP.NET" article here at CodeProject. It loads
the configuration settings and then renders the image, decrypting the security
code first. The security code is taken from DrawImage.aspx's How to use itThe demo application includes a ready-to-deploy sample, but there are a couple of things that would have to be done to an existing ASP.NET Web Form:
ConclusionThe controls are very simple and demonstrate how glorious ASP.NET's new architecture is. I hope people find it useful, and improve it. Apologies for not including many (if any) comments within the code, but since this article covers how it all works together it should be relatively to understand. As I revisit the solution I'll neaten things up a bit, one thing I would definitely like to do is produce a single control so that deployment is made even easier. Please feel free to post a message below or email me if you have any questions or comments. | ||||||||||||||||||||