Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Bot-Proof Submission Forms

2.36/5 (5 votes)
3 Apr 2008CPOL5 min read 1   118  
The following script makes it difficult for automatic tools to submit forms. The steps involved in this basic script are create a drawing space, allocate colors, fill the background, draw characters, add distortions, and output the image to the browser.
Article.GIF

Introduction

The following script makes it difficult for automatic tools to submit forms. The steps involved in this basic script are create a drawing space, allocate colors, fill the background, draw characters, add distortions, and output the image to the browser.

Drawing with GDI+

GDI+ is an all-purpose drawing model for .NET applications. GDI+ has a number of uses in .NET, including writing documents to the printer, displaying graphics in a Windows application, and rendering graphics in a web page. Using GDI+ code to draw a graphic is slower than using a static image file. However, it gives you much more freedom and enables several possibilities that weren't possible (or were prohibitively difficult) in earlier web development platforms, such as classic ASP. For example, you can create rich graphics that incorporate user-specific information, and you can render charts and graphs on the fly based on the records in a database. The heart of GDI+ programming is the System.Drawing.Graphics class. The Graphics class encapsulates a GDI+ drawing surface, whether it is a window, a print document, or an in-memory bitmap. ASP.NET developers rarely have the need to paint windows or print documents, so it’s the last option that is the most practical. To use GDI+ in ASP.NET, you need to follow a sequence of four steps:

  1. Create the in-memory bitmap where you'll perform all your drawing.
  2. Create a GDI+ graphics context for the image. This gives you the System.Drawing.Graphics object you need.
  3. Perform the drawing using the methods of the Graphics object. You can draw and fill lines and shapes, and you can even copy bitmap content from existing files.
  4. Write the binary data for the image to the browser, using the Response.OutputStream property.

In the following sections, you'll see several examples of web pages that use GDI+. Before continuing, you may want to ensure that the following namespaces are imported:

C#
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging; 

The System.Drawing namespace defines many of the fundamental ingredients for drawing, including pens, brushes, and bitmaps. By default, Visual Studio adds using statements that import these namespaces to all your web pages. The System.Drawing.Drawing2D namespace adds other useful details such as the flexible GraphicsPath class, while System.Drawing.Imaging includes the ImageFormat namespace that lets you choose the graphics format in which your bitmap will be rendered when it’s sent to the client.

Simple Drawing

The following example demonstrates the simplest possible GDI+ page. All the work is performed in the event handler for the Page.Load event. The first step is to create the in-memory bitmap by creating an instance of the System.Drawing.Bitmap class. When you create this object, you need to specify the height and width of the image in pixels as constructor arguments. You should make the size as small as possible. Not only will a larger bitmap consume additional server memory while your code is executing, but the size of the rendered content you send to the client will also increase, slowing down the transmission time.

C#
// Create the in-memory bitmap where you will draw the image. 
// This bitmap is 300 pixels wide and 50 pixels high. 
Bitmap image = new Bitmap(300, 50);

The next step is to create a GDI+ graphics context for the image, which is represented by the System.Drawing.Graphics object. This object provides the methods that allow you to draw content on the in-memory bitmap. To create a Graphics object from an existing Bitmap object, you just use the static Graphics.FromImage() method, as shown here:

C#
Graphics g = Graphics.FromImage(image);  

Now comes the interesting part. Using the methods of the Graphics class, you can draw text, shapes, and image on the bitmap. In this example, the drawing code is exceedingly simple. It fills the graphic with a solid white background using the FillRectangle() method of the Graphics object.

C#
// Draw a solid white rectangle. 
// Start from point (1, 1). 
// Make it 298 pixels wide and 48 pixels high. 
g.FillRectangle(Brushes.White, 1, 1, 298, 48);

The FillRectangle() method requires several arguments. The first argument sets the color, the next two parameters set the starting point, and the final two parameters set the width and height. When measuring pixels, the point (0, 0) is the top-left corner of your image in (X, Y) coordinates. The X coordinate increases as you go farther to the right, and the Y coordinate increases as you go farther down. In the current example, the image is 300 pixels wide and 50 pixels high, which means the point (300, 50) is the bottom-right corner. In this example, the FillRectangle() method doesn't quite fill the entire bitmap. Instead, it leaves a border 1-pixel wide all around. Because you haven't painted any content to this area, these pixels will have the default color (which, for a bitmap that you render to the GIF format, is black). The next portion of the drawing code renders a static label message. To do this, you need to create a System.Drawing.Font object that represents the font you want to use. This shouldn't be confused with the FontInfo object you use with ASP.NET controls to specify the requested font for a web page. Unlike FontInfo, Font represents a single, specific font (including typeface, size, and style) that’s installed on the current computer. When you create a Font object, you specify the font name, point size, and style, as shown here:

C#
Font font = new Font("Impact", 20, FontStyle.Regular);

***Because this image is generated on the server, you can use any font that the server has installed when creating the graphic. The client won't need to have the same font, because the client receives the text as a rendered image. To render the text, you use the DrawString() method of the Graphics object. As with the FillRectangle() object, you need to specify the coordinates where the drawing should begin. This point represents the top-left corner of the text block. In this case, the point (10, 5) is used, which gives a distance of 10 pixels from the left and 5 pixels from the top.

C#
g.DrawString("This is a test.", font, Brushes.Blue, 10, 5);

Once the image is complete, you can send it to the browser using the Image.Save() method. Conceptually, you “save” the image to the browser’s response stream. It then gets sent to the client and is displayed in the browser. When you use this technique, your image replaces any other webpage data and bypasses the web control model.

C#
// Render the image to the output stream.
 image.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);

You can save an image to any valid stream, including a FileStream. This technique allows you to save dynamically generated images to disk, so you can use them later in other web pages. Finally, you should explicitly release your image and graphics context when you're finished, because both hold onto some unmanaged resources that won't be released right away if you don't. You release resources by calling the Dispose() method, as shown here:

C#
g.Dispose();
image.Dispose();

Article2.GIF

Bot-proof Image Generator Code

C#
public partial class RndImg : System.Web.UI.UserControl 
{ 	
	private StringBuilder str = new StringBuilder();
	private bool ABrush = true;
	public bool DefaultRandomBrush
	{ 
		get { return ABrush; }
		set { ABrush = value; }
	} 
	private int backden = 500; 
	public int BackgroundDensity 
	{ 
		get { return backden; } 
		set { backden = value; } 
	} 
	public string Output() 
	{ 
		return Session["Out"].ToString(); 
	} 
	public void Fresh(object sender, EventArgs e) //For redraw bot-proof image
	{ 
		Page_Load(sender, e); 
	} 
	protected void Page_Load(object sender, EventArgs e) 
	{ 
		float temp = 0; 
		Random rnd = new Random(unchecked((int)DateTime.Now.Ticks)); 
		char ch = '1'; 
		Bitmap image = new Bitmap(180, 60); 
		Graphics g = Graphics.FromImage(image); 
		g.FillRectangle(Brushes.WhiteSmoke, 1, 1, 178, 58); 
		Font font = new Font("Monotype Corsiva", 30, FontStyle.Italic); 
		SizeF size = new SizeF(); 
		backbround(g, 180,60); 
		Brush[] myBrush ={Brushes.Red, 
				Brushes.Blue, 
				Brushes.DarkBlue, 
				Brushes.Violet, 
				Brushes.Tomato, 
				Brushes.Black, 
				Brushes.Chocolate, 
				Brushes.Brown}; 
		SolidBrush mysBrush; 
		for (int i = 0; i < 4; i++) 
		{ 
			ch = Convert.ToChar((int)((rnd.NextDouble() * 25) + 65)); 
			if (ABrush == false) 
			{ 
				mysBrush = new SolidBrush
				(Color.FromArgb((int)(rnd.NextDouble() * 255), 
				(int)(rnd.NextDouble() * 255), 
				(int)(rnd.NextDouble() * 255)));
				g.DrawString(ch.ToString(), font, 
				mysBrush, temp, (int)(rnd.NextDouble() * 20)); 
			} 
			else 
			{ 
				g.DrawString(ch.ToString(), font, 
				myBrush[(int)(rnd.NextDouble() * myBrush.Length)],
				temp, (int)(rnd.NextDouble() * 20)); 
			} 
			size = g.MeasureString(ch.ToString(), font); 
			temp += size.Width; 
			str.Append(ch); 
		} 
		image.Save(Server.MapPath("")+@"\a32166g9.gif", ImageFormat.Gif); 
		Page.Unload += new EventHandler(Page_Unload); 
	} 
	void Page_Unload(object sender, EventArgs e) 
	{ 
		Session["Out"] = str.ToString(); 
	} 
	private void backbround(Graphics gr, int width, int hieght)// 
	{ 
		Random rnd = new Random(unchecked((int)DateTime.Now.Ticks)); 
		int x2 = 0, y2 = 0; 
		int x = 0, y = 0; 
		for (int i = 0; i < backden; i++) 
		{ 
			x = (int)(rnd.NextDouble() * width); 
			y = (int)(rnd.NextDouble() * hieght); 
			x2 = (int)(rnd.NextDouble() * 5); 
			y2 = (int)(rnd.NextDouble() * 5); 
			Pen p = new Pen(Color.FromArgb((int)(rnd.NextDouble() * 255), 
				(int)(rnd.NextDouble() * 255), 
				(int)(rnd.NextDouble() * 255))); 
			gr.DrawLine(p, new Point(x, y), new Point(x + x2, y + y2)); 
		} 
	} 
}

History

  • 4th April, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)