This topic lists the steps to follow in order to create a custom strategy for spam protection and add it to Sitefinity. A sample strategy, Bot Trap Link, is described in
order to demonstrate how the steps are applied.
Creating a Custom Strategy
There are several steps to follow in order to create a custom strategy in Sitefinity:
-
Create a new class which inherits from SpamProtector. For example, name it MySpamProtector.
-
Create a new class which implements ISpamProtector. For example, name it MyStrategy.
-
Implement the custom logic in the class MyStrategy - use the methods and properties provided by the interface and add any new necessary methods and
properties.
-
Create a private instance of MyStrategy as an extender in the class MySpamProtector. For example, name it myStrategyInstance.
-
Add a constructor to the class MySpamProtector.
-
Add all the needed properties to the class MySpamProtector. Use them to access the properties on myStrategyInstance.
-
Add a boolean property to MySpamProtector which will enable the custom strategy - for example, EnableMyStrategy. Add
myStrategyInstance to the collection of spam protectors in the setter of this property:
|
Copy Code |
|
if (value)
{
this.spamProtectors.Add(this.myStrategyInstance);
}
|
-
Add MySpamProtector to the toolbox of Sitefinity’s Admin part. To do that, the protector should be added to
the <toolboxControls> tag in the web.config file.
Sample Implementation of a Bot Trap Link Strategy
This section describes the functionality of the sample custom strategy, lists the steps for its creation and the full code of the strategy.
 |
To download the code used in this topic (without the web.config changes), click here. |
Functionality Description
The Bot Trap Link strategy for spam detection is based on the assumption that an extremely small image would be invisible to humans but visible to bots. So, if there is a
link beneath that image and it gets opened, the executor should be a bot and the received data should be ignored.
The page that contains the form that should be filled by a user also contains an image with size 1 pixel and a link to an additional page. If the link is opened and
the page this link directs to is visited, the executor is assumed to be a bot. Therefore, a handler class (BotTrapLinkHandler) adds the GUID of the
page visitor and saves it in the cache. Afterwards, the BotTrapLink class checks if the current GUID is in the cache - if yes, the executor is a bot. This
means the submitted data should be discarded.
Steps for Creating the Bot Trap Link Strategy
Following are the same steps described in the beginning of this topic but now they demonstrate the creation of the sample Bot Trap Link strategy:
-
Create a new class which inherits from SpamProtector. Name it CustomSpamProtector.
| CustomSpamProtector.cs |
Copy Code |
|
public class CustomSpamProtector : SpamProtector
|
-
Create a new class which implements ISpamProtector. Name it BotTrapLink.
| BotTrapLink.cs |
Copy Code |
|
public class BotTrapLink : ISpamProtector
|
-
Implement the custom logic in the class BotTrapLink - use the methods and properties provided by the interface and add any new necessary methods and
properties.
-
Create a private instance of BotTrapLink as an extender in the class CustomSpamProtector. Name it botTrapLink.
| CustomSpamProtector.cs |
Copy Code |
|
private BotTrapLink botTrapLink;
|
-
Add a constructor to the class CustomSpamProtector.
| CustomSpamProtector.cs |
Copy Code |
|
public CustomSpamProtector()
{
botTrapLink = new BotTrapLink();
}
|
-
Add all the needed properties to the class CustomSpamProtector. Use them to access the properties on botTrapLink. For example:
| CustomSpamProtector.cs |
Copy Code |
|
public string BotTrapLinkMsg
{
get
{
return botTrapLink.ErrorMessage;
}
set
{
botTrapLink.ErrorMessage = value;
}
}
|
-
Add a boolean property to the CustomSpamProtector class which will enable the custom strategy. Name it EnableMyStrategy. Add
botTrapLink to the collection of spam protectors in the setter of this property:
| CustomSpamProtector.cs |
Copy Code |
|
public bool EnableBotTrapLink
{
get
{
return botTrapLink.IsEnabled;
}
set
{
botTrapLink.IsEnabled = value;
if (value)
{
this.spamProtectors.Add(this.botTrapLink);
}
}
}
|
-
Add MySpamProtector to the toolbox of Sitefinity’s Admin part. To do that, the protector should be added to
the <toolboxControls> tag in the web.config file:
| web.config |
Copy Code |
|
<toolboxControls>
...
<add name="Custom Spam Protector" section="Forms" type="SpamProtectionTest.CustomSpamProtector, SpamProtectionTest"
description="A different strategy."
/>
|
Implementing the Bot Trap Link Strategy
In order to implement the strategy, a new class library is created - SpamProtectionTest. It includes the three classes:
CustomSpamProtector.cs, BotTrapLink.cs, and BotTrapLinkHandler.cs. The solution of the class library is added
to a Sitefinity project. As the code in the following sections shows, there are classes and interfaces that need to be inherited or implemented to create a new strategy for
the spam protector (SpamProtector, ISpamProtector). Therefore, the Telerik.Cms.Web.UI assembly is added to the /bin folder of
SpamProtectionTest. Also, SpamProtectionTest is referenced in the Sitefinity project.
Following are four sections that give some detail and provide the code for the classes that need to be created or modified in order to implement the Bot Trap Link Strategy.
These the files are: web.config, CustomSpamProtector.cs, BotTrapLink.cs, and BotTrapLinkHandler.cs.
The web.config Class
Changes need to be made to the <modules> and <toolboxControls> sections of the configuration file. Also, if HTTPHandlers are used,
the handler should be declared in the <httpHandlers> section.
- The CustomSpamProtector module should be added to the <modules> tag of the <framework> section:
|
Copy Code |
|
<framework>
<modules>
<add type="SpamProtectionTest.CustomSpamProtector, SpamProtectionTest"/>
</modules>
|
-
To access the protector in the toolbox of the Admin part of Sitefinity and thus be able to add it to pages, the CustomSpamProtector should be added to the
<toolboxControls> section:
|
Copy Code |
|
<toolboxControls>
...
<add name="Custom Spam Protector" section="Forms" type="SpamProtectionTest.CustomSpamProtector, SpamProtectionTest"
description="A Bot Trap Link."
/>
|
-
The Bot Trap Link strategy uses http handlers so the following declaration should also be added to the web.config file.
 |
If any custom strategy uses HTTP handlers, the following setting should be added to the
<httpHandlers> section of the configuration file of the project that applies the strategy. |
|
Copy Code |
|
<httpHandlers>
<add verb="GET" path="BotHandler.axd"
type="SpamProtectionTest.BotTrapLinkHandler,
SpamProtectionTest"/> </httpHandlers>
|
The CustomSpamProtector.cs Class
The CustomSpamProtector class inherits SpamProtector.
| CustomSpamProtector.cs |
Copy Code |
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Telerik.Cms.Web.UI; using Telerik.Web.UI.SpamProtection; using System.ComponentModel; namespace SpamProtectionTest
{
public class CustomSpamProtector : SpamProtector
{
public CustomSpamProtector()
{
botTrapLink = new BotTrapLink();
}
/// <summary>
/// Saves any server control state changes that have occurred since the time the page was posted back to the
server.
/// </summary>
/// <returns>
/// Returns the server control's current state. If there is no state associated with the control, this method
returns null.
/// </returns>
protected override object SaveControlState()
{
object[] objects = { botTrapLink.PrevGuid };
return (object)objects;
}
/// <summary>
/// Loads the state of the control.
/// </summary>
/// <param name="state">The state.</param>
protected override void LoadControlState(object state)
{
if (state != null)
{
object[] objects = (object[])state;
botTrapLink.PrevGuid = (string)objects[0];
}
}
/// <summary>
/// Gets or sets a value indicating whether to enable auto bot discovery with bot trapped with link strategy
or not.
/// </summary>
/// <value>
/// <c>true</c> if auto bot discovery with bot trapped with link strategy is enabled;
otherwise, <c>false</c>.
/// </value>
[DefaultValue(false),
Description("Value indicating whether to enable auto bot discovery with bot trapped with link strategy
or not."),
Category("Auto Discovery - Bot Trap Link")]
public bool EnableBotTrapLink
{
get
{
return botTrapLink.IsEnabled;
}
set
{
botTrapLink.IsEnabled = value;
if (value)
{
this.spamProtectors.Add(this.botTrapLink);
}
}
}
/// <summary>
/// Gets or sets the auto bot discovery with bot trapped with link strategy error message.
/// </summary>
/// <value>The auto bot discovery with bot trapped with link strategy error message.</value>
[DefaultValue(""),
Description("Bot trapped with link strategy error message."),
Category("Auto Discovery - Bot Trap Link")]
public string BotTrapLinkMsg
{
get
{
return botTrapLink.ErrorMessage;
}
set
{
botTrapLink.ErrorMessage = value;
}
}
/// <summary>
/// Gets or sets the bot trapped with link strategy label for the invisible image.
/// </summary>
/// <value>The bot trapped with link strategy label for the invisible image.</value>
[DefaultValue(""),
Description("Bot trapped with link strategy label for the invisible image."),
Category("Auto Discovery - Bot Trap Link")]
public string BotTrapLinkLabel
{
get
{
return botTrapLink.LabelText;
}
set
{
botTrapLink.LabelText = value;
}
}
private BotTrapLink botTrapLink;
}
}
|
The BotTrapLinkHandler.cs Class
The BotTrapLinkHandler class is the bot trap stream HttpModule. It adds bot GUIDs to the cache.
| BotTrapLinkHandler.cs |
Copy Code |
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Web.Caching; using Telerik.Web.UI.SpamProtection.AutoBotDiscovery.Strategies; namespace SpamProtectionTest
{
/// <summary>
/// Bot trap stream HttpModule. Adds Bot Guids to the cache.
/// </summary>
public class BotTrapLinkHandler : IHttpHandler
{
#region IHttpHandler Members
/// <summary>
/// Gets a value indicating whether another request can use the <see
cref="T:System.Web.IHttpHandler"></see> instance.
/// </summary>
/// <value></value>
/// <returns>true if the <see cref="T:System.Web.IHttpHandler"></see> instance is reusable;
otherwise, false.</returns>
public bool IsReusable
{
get
{
return true;
}
}
/// <summary>
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see
cref="T:System.Web.IHttpHandler"></see> interface.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpContext"></see> object that
provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP
requests.</param>
public void ProcessRequest(HttpContext context)
{
HttpApplication app = context.ApplicationInstance;
// get the unique GUID of the captcha; this must be passed in via the querystring
string guid = app.Request.QueryString["guid"];
// Add (Guid, "BotGuid") pair to the Cache and make it expire after 5 minutes
if (!String.IsNullOrEmpty(guid))
{
HttpRuntime.Cache.Add(guid, "BotGuid",
null, DateTime.Now.AddMinutes(5),
Cache.NoSlidingExpiration,
CacheItemPriority.Normal, null);
}
app.Response.StatusCode = 200;
context.ApplicationInstance.CompleteRequest();
}
#endregion
}
}
|
The BotTrapLink.cs Class
The BotTrapLink class implements the ISpamProtector interface. The class checks if the current GUID is in the cache.
| BotTrapLink.cs |
Copy Code |
|
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; using System.Web; using Telerik.Cms.Web.UI; using Telerik.Web.UI.SpamProtection.AutoBotDiscovery.Strategies; using Telerik.Web.UI.SpamProtection;
namespace SpamProtectionTest
{
public class BotTrapLink : ISpamProtector
{
#region Public Properties
#region IAutoBotDiscoveryStrategy Members
/// <summary>
/// Gets an indicator wherher the user is validated ot not
/// </summary>
/// <value></value>
public bool IsValid
{
get
{
return isValid;
}
}
/// <summary>
/// Gets or sets an error message displayed when the user is not validated
/// </summary>
/// <value></value>
public string ErrorMessage
{
get
{
return errorMessage;
}
set
{
errorMessage = value;
}
}
/// <summary>
/// Gets or sets an indicator whether this spam protector is enabled or not
/// </summary>
/// <value></value>
public bool IsEnabled
{
get
{
return isEnabled;
}
set
{
isEnabled = value;
}
}
#endregion
#region Common Properties
/// <summary>
/// Gets or sets the label text.
/// </summary>
/// <value>The label text.</value>
public string LabelText
{
get
{
return labelText;
}
set
{
labelText = value;
}
}
/// <summary>
/// Gets or sets the GUID of the previous session.
/// </summary>
/// <value>The GUID of the previous session.</value>
public string PrevGuid
{
get
{
return prevGuid;
}
set
{
prevGuid = value;
}
}
#endregion
#endregion
#region Construction
/// <summary>
/// Initializes a new instance of the <see cref="BotTrapLink"/> class.
/// </summary>
public BotTrapLink()
{
this.isValid = true;
this.errorMessage =
string.Empty;
this.guid =
Guid.NewGuid().ToString();
// this will be used only in the begining and later will be
reassigned from the
// spam protection control's ControlState
this.prevGuid = this.guid;
}
#endregion
#region Methods
#region IAutoBotDiscoveryStrategy Members
/// <summary>
/// Add the child controls for this spam protector to the main contrainer with
controls
/// </summary>
/// <param name="container">The main container with controls</param>
public void AddChildControls(Control container)
{
// Create the 1px image
Image image = new
Image();
image.ID = "OnePxImage";
image.ImageUrl = "#";
image.Width = 1;
image.Height = 1;
image.AlternateText = "";
// Create the link to the bot trap and the 1px image
HyperLink linkToBotTrap = new
HyperLink();
linkToBotTrap.NavigateUrl = "BotHandler.axd?guid="
+ this.guid;
linkToBotTrap.Controls.Add(image);
// Create a hidden readonly textbox with the Bot Trap
Guid
TextBox botTrapGuidTextBox = new TextBox();
botTrapGuidTextBox.ID = "BotTrapGuid";
botTrapGuidTextBox.Text = this.guid;
botTrapGuidTextBox.ReadOnly = true;
botTrapGuidTextBox.Style[HtmlTextWriterStyle.Display] = "none";
// Create a hidden label and associate it with the bot trap
guid TextBox
Label hiddenLabel = new
Label();
hiddenLabel.ID = "BotTrapGuidLabel";
hiddenLabel.Text = this.labelText;
hiddenLabel.Style[HtmlTextWriterStyle.Display] = "none";
hiddenLabel.AssociatedControlID = botTrapGuidTextBox.ID;
// Add the link to the container
container.Controls.Add(hiddenLabel);
container.Controls.Add(linkToBotTrap);
container.Controls.Add(botTrapGuidTextBox);
}
/// <summary>
/// Load the post back data for the spam protector
/// </summary>
/// <param name="container">The main container with controls</param>
public void LoadPostBackData(Control container)
{
TextBox botTrapGuidTextBox = container.FindControl("BotTrapGuid") as TextBox;
if (botTrapGuidTextBox !=
null)
{
this.postData = botTrapGuidTextBox.Text;
}
}
/// <summary>
/// Validate the post back data
/// </summary>
public void ValidatePostBackData()
{
// Validation Rule: If in the Cache is value with the current
Guid then the Bot has visited
// BotHandler.aspx and a value has been added to the
Cache
if (!String.IsNullOrEmpty(this.prevGuid))
{
string cacheValue = HttpRuntime.Cache.Get(this.prevGuid) as
string;
this.isValid
= !(cacheValue == "BotGuid");
// Clear the cache and assign the new
guid on the place of the old one
// so that it can be added to the
cache once again if a bot visits the trap
RemoveGuidFromCache();
this.prevGuid = this.guid;
}
}
#endregion
#region Helper Methods
/// <summary>
/// Removes the GUID from cache.
/// </summary>
private void RemoveGuidFromCache()
{
HttpRuntime.Cache.Remove(this.prevGuid);
}
#endregion
#endregion
#region Private Fields
private bool isValid;
private bool isEnabled;
private string errorMessage;
private string postData;
private string guid;
private string prevGuid;
private string labelText;
#endregion
}
}
|
Testing the Bot Trap Link Strategy
In order to do a simple test of applying the Bot Trap Link strategy, a user control should be created and some settings should be done to the properties of the spam
protector.
A user control is created - TestSpamStrategyTextbox.ascx - and added to the main Sitefinity project. For the purpose of simple testing, it will only
contain a textbox and a label:
| TestSpamStrategyTextbox.ascx |
Copy Code |
|
<asp:TextBox ID="TextBox1" runat="server" />
<asp:Button ID="Button1" runat="server" />
|
This control should be added to the page that will use the spam protector. In order to be able to access the control in the Admin part of Sitefinity, the control should be
added to the <toolboxControls> section:
|
Copy Code |
|
<toolboxControls>
<add name="Test Form" section="Forms" url="~/UserControls/Forms/TestSpamStrategyTextbox.ascx" />
|
Go to the Advanced properties of the custom spam protector after adding it to the page in Page Edit mode. Add values to the two textbox properties in the
Auto Discovery - Bot Trap Link section: BotTrapLinkMsg and BotTrapLinkLabel. These messages will be displayed when a bot is
detected.
Change the size of the image to 100 for testing purposes in the BotTrapLink class. To do this, change the values of the image.Height and
image.Width properties of 1 to 100 like that:
| BotTrapLink.cs |
Copy Code |
|
public void AddChildControls(Control container)
{
// Create the 1px image
Image image = new Image();
image.ID = "OnePxImage";
image.ImageUrl = "#";
image.Width = 100;
image.Height = 100;
...
|
See Also