Mã nguồn ví dụ mẫu BotDetect ASP.NET 1.1 CAPTCHA - C#

Ví dụ mẫu sinh ngẫu nhiên BotDetect ASP.NET CAPTCHA cho bạn thấy việc sinh ngẫu nhiên các tham số của Captcha dễ dàng như thế nào, việc này làm tăng đáng kể tính bảo mật của CAPTCHA và đây là cách tốt nhất để tận dụng hết 50 giải thuật khác nhau của BotDetect.

Vị trí dự án mẫu

Mặc định, dự án mẫu này được cài đặt tại
C:\Program Files\Lanapsoft\BotDetect\ASP.NET 1.1\v2.0\Samples\CSharpBotDetect2RandomDemo\.

Bạn cũng có thể chạy nó từ Start Menu:
Programs > Lanapsoft > BotDetect > ASP.NET 1.1 > v2.0 > Samples > C# CAPTCHA Randomization Sample.

Default.aspx

Mã nguồn đầy đủ

<%@ Page language="c#" Codebehind="Default.aspx.cs" 
  AutoEventWireup="false" Inherits="CSharpBotDetectDemo._Default" %>

<%@ Register Assembly="Lanap.BotDetect" Namespace="Lanap.BotDetect" 
  TagPrefix="BotDetect" %>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>BotDetect Random Demo</title>
    <link type='text/css' rel='Stylesheet' href="StyleSheet.css" />
</head>
<body>
    <form id="form1" runat="server">
    <fieldset id="Preview">
        <legend>
            <span id="PreviewLegend">CAPTCHA Preview</span>
        </legend>
        <div id="PromptDiv">
            <span id="Prompt">Type the characters you see in 
              the picture</span>
        </div>
        <div id="CaptchaDiv">
            <BotDetect:Captcha ID="SampleCaptcha" runat="server" />
        </div>
        <div id="ValidationDiv">
            <asp:TextBox ID="CodeTextBox" runat="server">
            </asp:TextBox>
            <asp:Button ID="ValidateButton" runat="server" />
            <asp:Label ID="MessageCorrectLabel" runat="server">
            </asp:Label>
            <asp:Label ID="MessageIncorrectLabel" runat="server">
            </asp:Label>
        </div>
    </fieldset>
    <div id="Note">
        <span>NOTE: the Trial version will use "LANAP" instead of a 
          random code in 50% of renderings.</span>
    </div>
    </form>
</body>
</html>

Giải thích

Những dòng cần thiết để thêm BotDetect CAPTCHA vào trang ASP.NET và thực hiện việc xác thực sử dụng Ajax được tô đậm. Để sử dụng <BotDetect:Captcha>, trước hết chúng ta phải đăng ký Lanap.BotDetect.dll sử dụng <%@Register %>.

Trang web còn chứa <asp:TextBox> để người dùng nhập câu trả lời, một <asp:Button> để gửi câu trả lời, và một cặp <asp:Label> dùng để hiển thị kết quả xác thực. Phần còn lại của file được sinh ra bởi Visual Studio 2003, hoặc dùng để định nghĩa cách thức sắp xếp và hiển thị của trang.

Không có sự khác biệt nào giữa file .aspx của ví dụ này với file cơ bản, vì tất cả việc sinh ngẫu nhiên đều được thực hiện ở mã xử lý trang.

Default.aspx.cs

Mã nguồn đầy đủ

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace CSharpBotDetectDemo
{
    /// <summary>
    /// Mô tả tóm tắt cho lớp _Default.
    /// </summary>
    public class _Default : System.Web.UI.Page
    {
        protected Lanap.BotDetect.Captcha 
            SampleCaptcha;
						
        protected System.Web.UI.WebControls.Button 
            ValidateButton;
						
        protected System.Web.UI.WebControls.TextBox 
            CodeTextBox;
						
        protected System.Web.UI.WebControls.Label 
            MessageIncorrectLabel;
						
        protected System.Web.UI.WebControls.Label 
            MessageCorrectLabel;

        #region Web Form Designer generated code
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET 
            // Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
        }

        /// <summary>
        /// Phương thức cần thiết cho Designer - không được chỉnh sửa
        /// nội dung của phương thức này trong code editor.
        /// </summary>
        private void InitializeComponent()
        {    
            this.Init += new System.EventHandler(this.Page_Init);
						
            this.PreRender += 
                new System.EventHandler(this.Page_PreRender);
        }
        #endregion

        protected void Page_Init(object sender, EventArgs e)
        {
            /// register CAPTCHA-specific event handler
            SampleCaptcha.PreDrawCaptchaImage += 
                new PreDrawCaptchaImageHandler(
                this.SampleCaptcha_PreDrawCaptchaImage);
        }

        protected void Page_PreRender(object sender, EventArgs e)
        {
            /// initial page setup
            if (!IsPostBack)
            {
                /// set control text
                ValidateButton.Text = "Validate";
                MessageCorrectLabel.Text = "Correct!";
                MessageIncorrectLabel.Text = "Incorrect!";

                /// these messages are shown only after validation
                MessageCorrectLabel.Visible = false;
                MessageIncorrectLabel.Visible = false;
            }
			
			// clear user input on Reload button clicks
            string scriptTemplate = @"<script type='text/javascript'>
              function LBD_ClearUserInput() {{
                var LBD_textBox = document.getElementById('{0}');
                if(LBD_textBox) {{
                  LBD_textBox.value = '';
                }}
              }}
              LBD_RegisterHandler('PreReloadCaptchaImage', 
                LBD_ClearUserInput);
            </script>";
            ";
            string script = String.Format(scriptTemplate, 
              CodeTextBox.ClientID);
					
            if (!Page.IsClientScriptBlockRegistered(
                "CaptchaReloadClearInput"))
            {
              Page.RegisterClientScriptBlock("CaptchaReloadClearInput", 
                script);
            }

            // automatically lowercase user input
            CodeTextBox.Attributes.Add("onkeyup", 
                "this.value = this.value.toLowerCase();");

            if (IsPostBack)
            {
                /// validate the input code, and show the 
                /// appropriate message 
                string code = CodeTextBox.Text.Trim().ToUpper();
                if (SampleCaptcha.Validate(code))
                {
                    MessageCorrectLabel.Visible = true;
                    MessageIncorrectLabel.Visible = false;
                }
                else
                {
                    MessageCorrectLabel.Visible = false;
                    MessageIncorrectLabel.Visible = true;
                }

                /// clear previous user code input
                CodeTextBox.Text = null;
            }
        }
				
        /// <summary>
        /// Tác vụ ngẫu nhiên hoá CAPTCHA phải được thực hiện trong 
        /// hàm xử lý sự kiện này thay vì trong Page_Load hoặc Page_PreRender, 
        /// bởi vì sự kiện này cũng được phát ra khi truy cập trực tiếp vào hình ảnh CAPTCHA 
        /// ví dụ như khi click vào nút 
        /// Reload CAPTCHA liên tục 
		///</summary>
        void SampleCaptcha_PreDrawCaptchaImage(object sender, 
            EventArgs e)
        {
            ICaptcha captcha = sender as ICaptcha;
            if (captcha.CaptchaId != SampleCaptcha.CaptchaId)
            {
              return;
            }

            /// randomize code generation properties
            captcha.CodeType = RandomizationHelper.GetRandomCodeType();
				
            captcha.CodeLength = 
                RandomizationHelper.GetRandomCodeLength(4, 6);

            /// randomize text style
            TextStyleEnum[] styles = { 
                TextStyleEnum.Lego, TextStyleEnum.MeltingHeat, 
                TextStyleEnum.Ghostly, TextStyleEnum.FingerPrints, 
                TextStyleEnum.Graffiti2, TextStyleEnum.Bullets2, 
                TextStyleEnum.CaughtInTheNet2, TextStyleEnum.Collage, 
                TextStyleEnum.Chalkboard
            };
        
            captcha.TextStyle = 
                RandomizationHelper.GetRandomTextStyle(styles);
        }
    }
}

Giải thích

Trong quá trình Page_Init của trang ASP.NET, chúng ta đăng ký một phương thức xử lý sự kiện đặc biệt được thực thi trước mỗi lần hiển thị hình ảnh CAPTCHA, trong phương thức này chúng ta thực hiện việc sinh ngẫu nhiên. Vì các hình ảnh CAPTCHA được sinh ra và gửi tới máy khách trong một yêu cầu Http tách biệt khỏi yêu cầu tải trang ASP.NET (khi mã này được thực thi), chúng ta thêm phương thức xử lý sự kiện để đảm bảo các tham số của CAPTCHA được sinh ngẫu nhiên mỗi khi nó được vẽ, và không chỉ một lần khi trang được tải.

Điều này là quan trọng vì số lần yêu cầu hình ảnh CAPTCHA không nhất thiết phải bằng số lần tải trang - dễ thấy nhất là khi sử dụng nút Reload CAPTCHA, và khi bots truy cập trực tiếp vào hình ảnh CAPTCHA, hình ảnh CAPTCHA có thể được sinh ra chỉ sau một lần tải của trang (và thực thi hàm Page_PreRender tương ứng).

Trong phương thức Captcha_PreDrawCaptchaImage, đối tượng Captcha được truyền qua tham số sender. Để việc sinh ngẫu nhiên được thực hiện dễ dàng, chúng ta sử dụng lớp RandomizationHelper, cho phép chúng ta lấy giá trị ngẫu nhiên của một tham số cho trước từ một tập hợp các giá trị cho trước (ví dụ như CAPTCHA CodeType), hoặc một khoảng các giá trị (ví dụ như CAPTCHA CodeLength), hay từ một tập các giá trị (như CAPTCHA TextStyle).

Bạn cũng có thể sinh ngẫu nhiên các thông số khác của CAPTCHA với cách tương tự, nhưng giải thuật vẽ CAPTCHA và chiều dài ký tự CAPTCHA sẽ tăng tính bảo mật của CAPTCHA nhiều nhất khi chúng được sinh ngẫu nhiên. Mỗi giải thuật CAPTCHA riêng rẽ có thể bị bẻ gãy (nếu dành đủ công sức), nhưng nếu bot còn phải phân biệt từng giải thuật trong từng ảnh, nhiệm vụ sẽ khó khăn hơn gấp bội. Hơn nữa, nhiều giải thuật CAPTCHA phổ biến đã bị bẻ gãy vì nó dùng chiều dài ký tự cố định – "tìm 5 ký tự trong hình này" thì dễ hơn rất nhiều so với "tìm một số ký tự chưa biết trong hình này".

RandomizationHelper.cs

Mã nguồn đầy đủ

using System;
using System.Drawing;
using System.Collections;
using System.Collections.Specialized;
using System.Text;

using Lanap.BotDetect;

/// <summary>
/// Summary description for RandomizationHelper
/// </summary>
public sealed class RandomizationHelper
{
    private RandomizationHelper()
    {
        // constructor omitted, static methods only
    }

    /// a single global generator is used for all random numbers
    private static readonly Random _rand = new Random();

    public const CodeTypeEnum DefaultCodeType = 
        CodeTypeEnum.AlphaNumeric;

    public static CodeTypeEnum GetRandomCodeType(
        params CodeTypeEnum[] usedValues)
    {
        CodeTypeEnum codeType = DefaultCodeType;

        if (0 == usedValues.Length)
        {
            int max = Enum.GetValues(typeof(CodeTypeEnum)).Length;

            codeType = (CodeTypeEnum)(_rand.Next(max));
        }
        else if (1 == usedValues.Length)
        {
            codeType = usedValues[0];
        }
        else
        {
            int max = usedValues.Length;
            int index = _rand.Next(max);

            codeType = usedValues[index];
        }

        return codeType;
    }

    public const int DefaultCodeLength = 5;
    public const int MinCodeLength = 1;
    public const int MaxCodeLength = 15;

    public static int GetRandomCodeLength()
    {
        return GetRandomCodeLength(0, 0);
    }

    public static int GetRandomCodeLength(int max)
    {
        return GetRandomCodeLength(0, max);
    }

    public static int GetRandomCodeLength(int min, int max)
    {
        if ((max > MaxCodeLength) || (max < MinCodeLength))
        {
            max = MaxCodeLength;
        }

        if ((min < MinCodeLength) || (min > max))
        {
            min = MinCodeLength;
        }

        return _rand.Next(min, max + 1);
    }

    public static readonly ImageFormatEnum DefaultImageFormat = 
        ImageFormatEnum.Jpeg;

    public static ImageFormatEnum GetRandomImageFormat(
        params ImageFormatEnum[] usedValues)
    {
        ImageFormatEnum imageFormat = DefaultImageFormat;

        if (0 == usedValues.Length)
        {
            int max = Enum.GetValues(typeof(ImageFormatEnum)).Length;

            imageFormat = (ImageFormatEnum)(_rand.Next(max));
        }
        else if (1 == usedValues.Length)
        {
            imageFormat = usedValues[0];
        }
        else
        {
            int max = usedValues.Length;
            int index = _rand.Next(max);

            imageFormat = usedValues[index];
        }

        return imageFormat;
    }

    public static readonly Size DefaultImageSize = new Size(250, 50);
    public static readonly Size MinImageSize = new Size(50, 40);
    public static readonly Size MaxImageSize = new Size(500, 200);

    public static Size GetRandomImageSize()
    {
        return GetRandomImageSize(new Size(0, 0), new Size(0, 0));
    }

    public static Size GetRandomImageSize(Size maxSize)
    {
        return GetRandomImageSize(new Size(0, 0), maxSize);
    }

    public static Size GetRandomImageSize(Size minSize, Size maxSize)
    {
        /// determine width
        if ((maxSize.Width > MaxImageSize.Width) || 
            (maxSize.Width < MinImageSize.Width))
        {
            maxSize.Width = MaxImageSize.Width;
        }
        if ((minSize.Width < MinImageSize.Width) || 
            (minSize.Width > maxSize.Width))
        {
            minSize.Width = MinImageSize.Width;
        }
        int width = _rand.Next(minSize.Width, maxSize.Width + 1);

        /// determine height
        if ((maxSize.Height > MaxImageSize.Height) || 
            (maxSize.Height < MinImageSize.Height))
        {
            maxSize.Height = MaxImageSize.Height;
        }
        if ((minSize.Height < MinImageSize.Height) || 
            (minSize.Height > maxSize.Height))
        {
            minSize.Height = MinImageSize.Height;
        }
        int height = _rand.Next(minSize.Height, maxSize.Height + 1);

        /// the result
        return new Size(width, height);
    }

    public const TextStyleEnum DefaultTextStyle = 
        TextStyleEnum.Chalkboard;

    public static TextStyleEnum GetRandomTextStyle(
        params TextStyleEnum[] usedValues)
    {
        TextStyleEnum textStyle = DefaultTextStyle;

        if (0 == usedValues.Length)
        {
            int max = Enum.GetValues(typeof(TextStyleEnum)).Length;

            textStyle = (TextStyleEnum)(_rand.Next(max));
        }
        else if (1 == usedValues.Length)
        {
            textStyle = usedValues[0];
        }
        else
        {
            int max = usedValues.Length;
            int index = _rand.Next(max);

            textStyle = usedValues[index];
        }

        return textStyle;
    }
}

Giải thích

RandomizationHelper is a small utility class which you can use in your projects to simplify various CAPTCHA parameter randomization.

For each CAPTCHA parameter which can take a numeric or enumerated value, this class provides a static method returning a random value. Each parameter has a default value, and numeric parameters also have predefined minimum and maximum values.

All randomization methods take a variable number of parameters, either via multiple method overloads or via the params keyword.

Methods returning numeric values (for example, CodeLength) behave in the following manner:

  • If no parameters are given, the random value is selected between the predefined minimum and maximum values.
  • If a single value is given as a parameter, the random value is selected between the predefined minimum and the given value as the maximum. Note that it is not possible to use a maximum greater than the predefined one, only a lesser one.
  • If two values are given as parameters, the random value is selected between the first value as the minimum and the second value as the maximum. Note that it is not possible to use a maximum greater than the predefined one, or a minimum lesser than the predefined one.

Methods returning enumerated values (for example, CodeType) behave in the following manner:

  • If no parameters are given, the random value is selected from all possible enumeration values.
  • If a single value is given as the parameter, it is returned as the result - be careful not to pass a single value to these methods, since there will be no randomization. And if you want to use a single value, just assign it to the appropriate parameter directly.
  • If a set (i.e. an array) of values is given as the parameter, the random value is selected from within that set.

Of course, you could also use such randomization code directly in your projects, but encapsulating it in the RandomizationHelper class is made available for convenience and better code readability.

Web.config

Mã nguồn đầy đủ

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    
  <system.web>
  
  <httpHandlers>
    <add verb="*" path="LanapCaptcha.aspx" 
      type="Lanap.BotDetect.CaptchaHandler, Lanap.BotDetect"/>
  </httpHandlers>

  <!--  DYNAMIC DEBUG COMPILATION
    Set compilation debug="true" to enable ASPX debugging. Otherwise, 
    setting this value to false will improve runtime performance of 
    this application. Set compilation debug="true" to insert debugging 
    symbols (.pdb information) into the compiled page. Because this 
    creates a larger file that executes more slowly, you should set 
    this value to true only when debugging and to false at all other 
    times. For more information, refer to the documentation about 
    debugging ASP.NET files.
  -->
  <compilation 
    defaultLanguage="c#"
    debug="false"
  />

  <!--  CUSTOM ERROR MESSAGES
    Set customErrors mode="On" or "RemoteOnly" to enable custom error 
    messages, "Off" to disable. 
		
    Add <error> tags for each of the errors you want to handle.

    "On" Always display custom (friendly) messages.
		
    "Off" Always display detailed ASP.NET error information.
		
    "RemoteOnly" Display custom (friendly) messages only to users not 
      running on the local Web server. This setting is recommended for 
      security purposes, so that you do not display application detail 
      information to remote clients.
  -->
  <customErrors 
    mode="RemoteOnly" 
  /> 

  <!--  AUTHENTICATION 
    This section sets the authentication policies of the application. 
    Possible modes are "Windows", "Forms", "Passport" and "None".

    "None" No authentication is performed. 
		
    "Windows" IIS performs authentication (Basic, Digest, or 
    Integrated Windows) according to its settings for the 
    application. Anonymous access must be disabled in IIS. 
		
    "Forms" You provide a custom form (Web page) for users to 
    enter their credentials, and then you authenticate them 
    in your application. A user credential token is stored 
    in a cookie.
		
    "Passport" Authentication is performed via a centralized 
    authentication service provided by Microsoft that offers 
    a single logon and core profile services for member sites.
  -->
  <authentication mode="Windows" /> 

  <!--  AUTHORIZATION 
    This section sets the authorization policies of the 
    application. You can allow or deny access to application 
    resources by user or role. Wildcards: "*" mean everyone, 
    "?" means anonymous (unauthenticated) users.
  -->

  <authorization>
    <allow users="*" /> <!-- Allow all users -->
    <!-- 
    <allow users="[comma separated list of users]"
      roles="[comma separated list of roles]"/>
    <deny users="[comma separated list of users]"
      roles="[comma separated list of roles]"/>
    -->
  </authorization>

  <!--  APPLICATION-LEVEL TRACE LOGGING
    Application-level tracing enables trace log output for 
    every page within an application. 
    Set trace enabled="true" to enable application trace 
    logging. If pageOutput="true", the trace information 
    will be displayed at the bottom of each page. Otherwise, 
    you can view the application trace log by browsing the 
    "trace.axd" page from your web application root. 
  -->
  <trace
    enabled="false"
    requestLimit="10"
    pageOutput="false"
    traceMode="SortByTime"
    localOnly="true"
  />

  <!--  SESSION STATE SETTINGS
    By default ASP.NET uses cookies to identify which requests 
    belong to a particular session. If cookies are not available, 
    a session can be tracked by adding a session identifier to the 
    URL. To disable cookies, set sessionState cookieless="true".
  -->
  <sessionState 
    mode="InProc"
    stateConnectionString="tcpip=127.0.0.1:42424"
    sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
    cookieless="false" 
    timeout="20" 
  />

  <!--  GLOBALIZATION
    This section sets the globalization settings of the application. 
  -->
  <globalization 
    requestEncoding="utf-8" 
    responseEncoding="utf-8" 
  />
   
 </system.web>

</configuration>

Giải thích

Những dòng cần thiết để BotDetect CAPTCHA hoạt động đúng được tô đậm, những dòng khác là giá trị chuẩn được sinh ra bởi Visual Studio 2003. Không có thiết lập đặc biệt nào liên quan đến sinh ngẫu nhiên CAPTCHA trong file web.config.

Thành tố <httpHandlers> đăng ký đường dẫn sử dụng cho hình ảnh và âm thanh CAPTCHA được xử lý bởi Lanap.BotDetect.dll code. Thành tố <system.webServer> được sử dụng với cùng mục đích, nhưng chỉ được sử dụng cho IIS 7.0.

Khai báo validateIntegratedModeConfiguration="false" đảm bảo rằng file web.config có thể được xử lý bởi phiên bản cũ hơn của IIS (5.1, 6.0) cũng như phiên bản 7.0. Vì cú pháp đăng ký HttpHandler khác nhau giữa các phiên bản IIS và chế độ tích hợp ASP.NET, dùng cả hai thành tố trên giúp cho file web.config tương thích với tất cả các phiên bản IIS được hỗ trợ.

Thành tố <sessionState> khai báo cơ chế lưu trữ được sử dụng bởi BotDetect để lưu mã CAPTCHA và thiết lập cho mỗi người dùng. Thuộc tính Session State modes, providers, timeouts và cookieless attribute có thể được sử dụng, nhưng thành tố sessionIDManagerType được sử dụng để sửa lỗi gây bởi Windows Media Player 11 khi yêu cầu âm thanh CAPTCHAs (như được giải thích trong mục hỏi đáp).

Phiên bản hiện tại của BotDetect

Xin lưu ý

Trang này là bản dịch tiếng Việt không chính thức của trang gốc tiếng Anh: BotDetect ASP.NET 2.0 CAPTCHA Randomization C# Code Sample và có thể không chính xác, không đầy đủ hoặc không cập nhật.

Cập nhật ngày 2009-11-30. Áp dụng cho BotDetect ASP.NET CAPTCHA v2.0.15 và BotDetect ASP CAPTCHA v2.0.9.

language: English Español Tiếng Việt