Click here to Skip to main content
15,888,984 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I need to add a challenge response for a form submission to a mobile website. The traditional two word captcha I think will annoy mobile users and detract from the experience.

Does anyone have experience offering challenge response within mobile websites? Can they recommend a product for delivering this?
Posted
Updated 18-Jun-12 2:26am
v3
Comments
Farhan Ghumra 18-Jun-12 8:17am    
which language are you using ?
Stephen Hewison 18-Jun-12 8:27am    
ASP.Net, MVC, C#

 
Share this answer
 
v2
Comments
Stephen Hewison 18-Jun-12 8:38am    
Thanks for the links, but both of those would create accessibility issue for colour blind users without an audible alternative. If you're not providing an audible alternative it has to be one colour which is dark otherwise those suffering with Trichromacy (The most common type of colour blindness) may struggle with the response. The image must also be high contrast for those who suffer from Monochromacy.
Well as no-one answered in the time it took to build my own I though I'd tell you how I did it instead. My application already contains an UI component for a number key pad. I've reused this and written my own code to generate a number Captcha image. The rendered number is stored server side in the session and the number submitted by the user is validated against this.

The image generated is a number with a wave distortion, image fuzzing with further noise added by including pre and post wave distortion lines.

This is the settings class I put together:

C#
public class Settings
{

  public Settings(string text)
  {
    Text = text;
    Foreground = Color.Black;
    Background = Color.White;
    Width = 350;
    Height = 100;
    FontFamily = "Arial";
    FontHeight = 60;
    WaveAmplitude = 13;
    WaveLength = 125;
    FuzzAmount = 1;
    LineCount = 6;
  }

  public string Text { get; set; }
  public Color Foreground { get; set; }
  public Color Background { get; set; }
  public int Width { get; set; }
  public int Height { get; set; }
  public string FontFamily { get; set; }
  public int FontHeight { get; set; }
  public int WaveAmplitude { get; set; }
  public int WaveLength { get; set; }
  public int FuzzAmount { get; set; }
  public int LineCount { get; set; }
}


Next I created a class which applies a sine wave transition along the Y axis based on the current position on the X axis. The amounts are controled by the WaveAmplitude and WaveLength settings.

C#
public class WaveFunction
{

  private Settings _settings;

  public WaveFunction(Settings settings)
  {
    _settings = settings;
  }

  public int WaveAdjustment(int x)
  {

    double wl = (double)_settings.WaveLength;
    double wa = (double)_settings.WaveAmplitude;
    double dx = (double)x;

    dx = dx % wl;

    double d = dx / wl * 360;

    return (int)Math.Round(Math.Sin(Radians(d)) * wa);

  }

  private double Radians(double degrees)
  {
    return Math.PI * degrees / 180.0;
  }

}


Next I created the image drawer class:

C#
  public class ImageDrawer
  {

    Settings _settings;

    public ImageDrawer(Settings settings)
    {
      _settings = settings;
    }

}


Then I added the base image rendering method. This draws the text centred in the image. This uses the following settings to create the base image. Width, Height, Foreground, Background, FontFamily, FontSize

C#
private System.Drawing.Bitmap BaseImage()
{

  System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(_settings.Width, _settings.Height);

  using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
  {

    g.FillRectangle(new System.Drawing.SolidBrush(_settings.Background), new System.Drawing.Rectangle(0, 0, _settings.Width, _settings.Height));

    System.Drawing.Font font = new System.Drawing.Font(_settings.FontFamily, _settings.FontHeight);

    System.Drawing.SizeF textSizeF = g.MeasureString(_settings.Text, font);

    System.Drawing.Size textSize = new System.Drawing.Size((int)Math.Round(textSizeF.Width), (int)Math.Round(textSizeF.Height));

    System.Drawing.Point p = new System.Drawing.Point(_settings.Width / 2, _settings.Height / 2);

    System.Drawing.Point dp = new System.Drawing.Point(p.X - (textSize.Width / 2), p.Y - (textSize.Height / 2));

    System.Drawing.PointF dpF = new System.Drawing.PointF(dp.X, dp.Y);

    g.DrawString(_settings.Text, font, new System.Drawing.SolidBrush(_settings.Foreground), dpF);

    return bmp;

  }

}


The next method adds a number of lines randomly to the image. The method uses the following settings: Foreground, Width, Height, LineCount

C#
private System.Drawing.Bitmap AddLines(System.Drawing.Bitmap flat)
{

  using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(flat))
  {

    Random r = new Random();

    for (int i = 0; i < _settings.LineCount; i++)
    {

      int x = r.Next(0, _settings.Width);
      int y = r.Next(0, _settings.Height);
      int x2 = r.Next(0, _settings.Width);
      int y2 = r.Next(0, _settings.Height);

      System.Drawing.Point p1 = new System.Drawing.Point(x, y);
      System.Drawing.Point p2 = new System.Drawing.Point(x2, y2);

      g.DrawLine(new System.Drawing.Pen(_settings.Foreground), p1, p2);

    }


  }


  return flat;

}


Now the method which adds the wave distortion. This method uses the WaveFunction class. It creates a new image with the background colour then for each pixel in the original image, uses the WaveFunction class to calculate it's vertical offset and where the offset position is within the bounds of the image it applies the pixel to the new image.

C#
private System.Drawing.Bitmap AddWave(System.Drawing.Bitmap flat)
{

  WaveFunction wf = new WaveFunction(_settings);

  System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(_settings.Width, _settings.Height);

  using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
  {

    g.FillRectangle(new System.Drawing.SolidBrush(_settings.Background), new System.Drawing.Rectangle(0, 0, _settings.Width, _settings.Height));



  }

  for (int x = 0; x < _settings.Width; x++)
    for (int y = 0; y < _settings.Height; y++)
    {

      int newY = wf.WaveAdjustment(x);

      if (y + newY >= 0 && y + newY < _settings.Height)
      {
        bmp.SetPixel(x, y + newY, flat.GetPixel(x, y));
      }

    }

  return bmp;

}


The last method which changes the image is the fuzz method. This method randomly relocates each pixel of the image upto + or - number number of pixels stated in the FuzzAmount setting.

C#
private System.Drawing.Bitmap AddFuzz(System.Drawing.Bitmap flat)
{

  WaveFunction wf = new WaveFunction(_settings);

  System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(_settings.Width, _settings.Height);

  using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
  {

    g.FillRectangle(new System.Drawing.SolidBrush(_settings.Background), new System.Drawing.Rectangle(0, 0, _settings.Width, _settings.Height));



  }

  Random r = new Random();

  for (int x = 0; x < _settings.Width; x++)
    for (int y = 0; y < _settings.Height; y++)
    {

      int newX = x + (r.Next(-_settings.FuzzAmount, _settings.FuzzAmount));
      int newY = y + (r.Next(-_settings.FuzzAmount, _settings.FuzzAmount));

      if (newX >= 0 && newX < _settings.Width && newY >= 0 && newY < _settings.Height)
      {
        bmp.SetPixel(newX, newY, flat.GetPixel(x, y));
      }

    }

  return bmp;

}


The only thing left to do was to tie all the various methods together:

C#
public System.Drawing.Bitmap GetImage()
{


  System.Drawing.Bitmap bmp = BaseImage();
  bmp = AddLines(bmp);
  bmp = AddWave(bmp);
  bmp = AddLines(bmp);
  bmp = AddFuzz(bmp);

  return bmp;


}
 
Share this answer
 
v3

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900