My Links

Archives

Anti-Spam inputs using random client IDs (from: Brian Scott)

Recently I have been thinking about ways to make it harder for spam bots to submit blog comments or any other type of spam. Most likely they are sending out custom POST requests to comment pages where the name or ID of the form fields is well known.  It is just a simple matter of supplying values for those field names and posting the request to the appropriate url.

The solution I thought about was giving all the input fields random IDs.  The IDs should change for each new request to the page, except on postback.  However, I was not sure how this would work with the page lifecycle and postbacks.  Would I still be able to easily access the control by the ID I explicitly assigned it.  If not, how much work would it be to find a control by the random ID that is generated at runtime for each new non-postback request.

I sat down played with a TextBox on an aspx page for a couple minutes. I discovered it is much simpler than I originally thought it would be.  Changing the ID in the Page_Load event didn’t affect my ability to access the TextBox by the original ID I had explicitly assigned it.  In order to restore the ID on a postback, I put the generated ID into a session variable identified by the ClientID that ASP.NET generates. On a postback, the TextBox ID is restored to the generated ID.  On all new requests, a new random ID is generated.

Next, I sub-classed a TextBox and dropped the code in the OnLoad override.  I was happy to see that I could use this control exactly like a regular TextBox with no additional or different programming.  The ID on the client changed with each new request, but my code behind did not care. 

Here is the code:

[DefaultProperty("Text"),
   
ToolboxData("<{0}:AntiSpamTextBox runat=server>")]
public class AntiSpamTextBox : TextBox
{
    public AntiSpamTextBox() 
    {}

    protected override void OnLoad(System.EventArgs e)
    {
        HttpContext context = HttpContext.Current;
        if(!Page.IsPostBack)
        {
            string id = Guid.NewGuid().ToString("N");
            context.Session.Add(ClientID, id);
            ID = id;
        }
        else
        {
            ID = context.Session[ClientID].ToString();
        }

        base.OnLoad (e);
    }
}

This may be over simplistic, but it seems like it would help.  I tested multiple controls on one page and they all performed as expected, each having a different, random ID.  I was also able to correctly access each controls value in the code behind during a postback.  As is, the control still needs some code to deal with expired sessions, but I'm still thinking about the best way to persist the ID between requests.  Viewstate may work.

I used the ClientID because at that point in the code, the ClientID is still the unique ID generated by ASP.NET.  It seemed like a good candidate to distinguish between multiple controls on the same page.

Anyone else think this could be useful?  Any thoughts on other ways to do it? 

posted on Saturday, February 19, 2005 6:48 PM

sales@tourneylogic.com Copyright © Tourney Logic