meekob

ป้องกันการโพสต์ข้อความไม่พึงประสงค์ด้วย CAPTCHA ตอนที่ 2

เรตติ้ง
เขียนโดย Suwitcha Chandhorn เมื่อวันที่ 31 March 2008 ตอน 23:21

ความเดิมจากตอนที่แล้ว เราเริ่มต้นด้วยการสร้างคลาสสำหรับสร้างรูปภาพ CAPTCHA ขึ้นมาคลาสหนึ่งให้ชื่อว่า CaptchaImage และได้อธิบายวิธีโครงสร้างของมันไปพอสมควร คราวนี้เราจะมาดูกันถึงวิธีการเรียกใช้งานคลาสดังกล่าวนี้จากหน้าเว็บเพจใน ASP.Net กันดูบ้างดีกว่า

ดังที่เคยกล่าวไว้ในฉบับที่แล้ว การสร้าง Captcha แบบง่ายๆขึ้นใช้งานนั้น ทำได้โดยการสร้างคลาสสำหรับใช้ Generate Captcha ที่ต้องการขึ้นมาก่อน เมื่อต้องการใช้ก็เรียกใช้งานคลาสนั้น โดยผ่านข้อความที่สุ่มขึ้นมาเข้าไปเพื่อให้ได้รูปภาพกลับคืนมาแสดงผล นอกจากนี้เราต้องเก็บข้อความที่สร้างขึ้นไว้ใน Session เพื่อนำมาเทียบกับสิ่งที่ผู้ใช้ป้อนในภายหลัง ถ้าหากป้อนข้อความกลับมาได้ถูกต้อง จึงอนุญาตให้ผู้ใช้ทำงานต่อไปได้ ดังนั้นขั้นตอนถัดไปเราจึงต้องสร้างเว็บเพจที่จะเรียกใช้ CaptchaImage ขึ้นมา

เรียก CAPTCHA มาแสดงผล

ก่อนอื่นเราต้องแสดงผลรูปภาพที่ได้จากคลาสโดยการเรียกผ่านเว็บเพจเสียก่อน เพื่อจะทำให้สามารถเรียกใช้งานผ่านอินเทอร์เน็ตได้ ซึ่งทำได้ง่ายๆโดยการเพิ่ม WebForm ชื่อ GetCaptchaImage เข้ามาในโปรเจ็ค และเพิ่มโค้ดดังรายการที่ 1 เข้าไปในอีเวนท์ Page_Load โค้ดจะทำการสร้างรูปภาพขึ้นจากข้อความที่เราเก็บไว้ในตัวแปร Session ตามขนาดและตัวอักษรที่เรากำหนด และส่งผลกลับออกไปยังเว็บเพจที่เรียกมาเป็นไฟล์ชนิด Jpeg ซึ่งเป็นรูปแบบการแสดงผลรูปภาพมาตรฐานหนึ่งในอินเทอร์เน็ตโดยการกำหนดค่า ContentType ของ Request ที่เข้ามา ทำให้เราไม่จำเป็นจะต้องแก้ไขโค้ดใดๆในส่วนของไฟล์ .aspx เพิ่มเติม เนื่องจากค่าที่ได้จะถูกคืนไปเป็นรูปภาพเมื่อเว็บเพจถูกเรียกใช้แทน

รายการที่ 1: การเรียกใช้คลาส CaptchaImage และส่งคืนรูปภาพชนิด Jpeg

Partial Class GetCaptchaImage

    Inherits System.Web.UI.Page

   

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim ci As New CaptchaImage(Session("captchaCode").ToString(), 240, 60, "Tahoma")

        Me.Response.Clear()

        Me.Request.ContentType = "image/jpeg"

        ci.Image.Save(Me.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)

        ci.Dispose()

    End Sub

End Class

สร้างฟอร์มสำหรับแสดงและเทียบข้อความ

จากนั้นเราต้องสร้างฟอร์มขึ้นมาสำหรับแสดงและรับค่าเพื่อเทียบหาความถูกต้องเสียก่อน โดยการเพิ่มฟอร์มใหม่เข้ามาในโปรเจ็ค และเพิ่มคอนโทรลต่างๆ ดังตารางที่ 1 เราแสดงผลข้อความที่จะสุ่มขึ้นโดยใช้ Image คอนโทรลโดยกำหนด ImageUrl ไปยังไฟล์ GetCaptchaImage.aspx ที่เราเพิ่งสร้างขึ้น เมื่อโหลดคอนโทรลจะไปเรียกใช้ไฟล์ดังกล่าวและได้ค่าคืนมาเป็นรูปภาพอีกต่อหนึ่ง ทำให้เราไม่จำเป็นต้องสร้างรูปภาพจริงๆเตรียมไว้ในระบบ

ตารางที่ 1: คอนโทรลต่างๆที่ใช้ในเว็บเพจ

Control Property Value
Image ID imgCaptcha
  ImageUrl ~/GetCaptchaImage.aspx
TextBox ID txtMessage
Button ID btnCheck
  Text Check
Label ID lblIsMatched

นอกจากนี้เรายังต้องมีกล่องข้อความ, ปุ่ม และแถบข้อความเพื่อใช้แสดงผลการเปรียบเทียบ เมื่อใส่คอนโทรลต่างๆเข้ามาแล้วควรจัดให้เป็นระเบียบสวยงาม เพื่อให้ง่ายต่อการใช้งาน

รูปที่ 1

รูปที่ 1: การจัดวางคอนโทรลต่างๆใน IDE

สุ่มข้อความใน Code Behind

เมื่อจัดแต่งหน้าตาเสร็จ เราต้องมีการสุ่มข้อความหรือในที่นี้คือชุดตัวเลขขึ้นมา โดยทำการเขียนโค้ดไว้ในอีเวนท์ Page_Load ในส่วน Code Behind ของเว็บเพจที่จะใช้ โดยเลือกสุ่มค่าเพื่อมาเก็บไว้ในตัวแปร Session แล้วจึงใช้ค่านั้นสอบเทียบกันเมื่อเกิดการ PostBack ในเว็บเพจ ในโค้ดตัวอย่าง เราจะทำการสุ่มค่าตัวเลขหกหลักขึ้นมาหนึ่งชุดเมื่อเว็บเพจนั้นถูกเรียกใช้ในครั้งแรก และเก็บค่าไว้ในตัวแปร Session เมื่อ Image คอนโทรลถูกโหลดมันจะวิ่งไปเรียกไฟล์ GetCaptchaImage.aspx ซึ่งจะคืนค่ารูปตามตัวแปรที่เก็บไว้กลับมาเพื่อแสดงผล หากเรากรอกข้อมูลแล้วกดปุ่ม Check โปรแกรมก็จะทำการตรวจสอบค่าที่เราป้อนเข้ามากับตัวแปรที่เก็บไว้ใน Session ก่อนจะแสดงผลการเปรียบเทียบออกมาทางหน้าจอ

รายการที่ 2: การสุ่มค่าข้อความเพื่อใช้ตรวจสอบ

Partial Class _Default

    Inherits System.Web.UI.Page

 

    Private Function GenerateRandomCode() As String

        Dim s As String = String.Empty

        Dim r As New Random

 

        For i As Integer = 0 To 6

            s = String.Concat(s, r.Next(10).ToString())

        Next

 

        Return s

    End Function

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not Page.IsPostBack Then

            Session("captchaCode") = GenerateRandomCode()

        Else

            If Not String.IsNullOrEmpty(Session("captchaCode").ToString()) AndAlso txtMessage.Text = _

                Session("captchaCode").ToString() Then

                lblIsMatched.Text = "Matched!"

            Else

                lblIsMatched.Text = "Not match, try again!"

                txtMessage.Text = String.Empty

                Session("captchaCode") = GenerateRandomCode()

            End If

        End If

    End Sub

End Class

ปรับแต่งรูปแบบการแสดงผล

หากเราทดสอบการใช้งานได้ผลสำเร็จเป็นที่น่าพอใจแล้ว เราก็สามารถที่จะปรับแต่งรูปแบบการแสดงผลให้เป็นไปตามรูปแบบที่เราต้องการได้ หากต้องการเปลี่ยนข้อความที่สุ่มขึ้นก็สามารถทำได้เลยโดยการแก้ไขอัลกอริทึมของฟังก์ชั่น GenerateRandomCode() ในอีเวนท์ Page_Load ของเว็บเพจที่เรียกใช้ GetCaptchaImage.aspx แต่ถ้าหากต้องการปรับวิธีการแสดงผลของภาพ ก็ต้องย้อนกลับไปดูโค้ดในคลาส CaptchaImage กันครับ

ในการสร้างและปรับแต่งรูปภาพแบบ 2D หรือ 2 dimension (สองมิติ) เนมสเปซที่เกี่ยวข้องจะอยู่ในชุดของ System.Drawing ซึ่งมีเนมสเปซย่อยๆที่จำเป็นต้องเรียกใช้งานอีกหลายเนมสเปซ เช่น System.Drawing.Drawing2D, System.Drawing.Graphics และ System.Drawing.Imaging เป็นต้น เราต้องทำการอิมพอร์ตเข้ามาก่อนจึงจะสามารถเรียกใช้งานคลาสและฟังก์ชั่นต่างๆที่เกี่ยวกับกราฟิกใน .Net Framework 2.0 หรือ GDI+ ได้

เราเริ่มสร้าง Captcha ของเราโดยการสร้างออปเจ็คต์ Bitmap ขึ้นมาก่อน จากนั้น Reference ไปยังคลาส Graphics เพื่อกำหนดให้เป็นพื้นที่ที่ใช้ในการเขียนกราฟิกต่างๆลงไปได้ เมื่อ New Bitmap เรากำหนดให้มีความกว้าง ความสูง และรูปแบบการแสดงผลผ่าน PixelFormat.Format32bppPArgb ซึ่งหมายถึง เรากำหนดรูปแบบของกราฟิกในรูปให้มีขนาด 32 บิตต่อจุด (pixel) และกำหนดค่าสีแบบ Premultiplied Alpha

หลายคนอาจจะสงสัยว่า Premultiplied Alpha คืออะไร ขออธิบายโดยย่อว่า ในการแสดงค่าสีบนจอ เรามีแม่สีทั้งหมดสามสี นั่นคือ แดง เขียว น้ำเงิน สีอื่นๆจะเกิดจากการผสมระหว่างแม่สีสามสีนี้ แต่ในกรณีที่เราต้องการควบคุมความเข้มหรือจางของสี เราต้องกำหนดไว้ที่ค่า Alpha นั่นเอง ยกตัวอย่างเช่น จุดจุดหนึ่งเก็บค่าสีเรียงตามลำดับดังนี้ (r, g, b, a) หากเราต้องการแสดงสีขาว ก็ต้องเก็บค่าเป็น (1,1,1,1) หากต้องการให้โปร่งใสก็ต้องเก็บค่าเป็น (0,0,0,0) เป็นต้น ถ้าเป็นในกรณีที่เราเก็บค่าสีแบบ Premultiplied Alpha ค่าสีจะถูกเก็บแบบ (ar, ag, ab, a) ดังนั้นในกรณีที่เราต้องการแสดงผลเป็นสีขาวโปร่ง (50% White) การเก็บค่าสีแบบ Alpha จะให้ผลเป็นสีเทาเพราะเก็บค่า Alpha ไว้ที่เดียว ในขณะที่การเก็บแบบ Premultiplied Alpha จะให้ค่าสีขาว 50% ได้เพราะเก็บในลักษณะแยกช่องกัน (0.5,0.5,0.5,0.5) จึงสามารถแสดงผลได้ถูกต้องกว่านั่นเอง

จากนั้นเราก็จะทำการวาดพื้นที่สี่เหลี่ยมตามความกว้าง ความสูงที่เรากำหนดลงไปแล้วระบายด้วย HatchBruch หรือลวดลายที่กำหนด ซึ่งในตัวอย่างนี้ก็คือ HatchBrush.SmallGrid หรือรูปสี่เหลี่ยมเล็กนั่นเอง หากเราเปลี่ยนคุณสมบัตินี้ก็จะทำให้เราได้ลวดลายของพื้นหลัง CAPTCHA ที่แตกต่างออกไป ตัวอย่างลวดลายที่น่าสนใจก็มี เช่น DottedGrid, SmallConfetti เป็นต้น เราสามารถดูตัวอย่างของ HatchStyle แบบต่างๆได้ที่ http://www.drewnoakes.com/snippets/GdiColorChart/

รูปที่ 2

รูปที่ 2: ตัวอย่างแบบต่างๆของ HatchStyle

ขั้นต่อไปเราจะหาขนาดที่เหมาะสมของแบบตัวอักษรที่เราจะใช้ โดยการกำหนดให้ขนาดเริ่มแรกเท่ากับความสูงของสี่เหลี่ยมที่เราสร้างขึ้นเสียก่อน จากนั้นจึงวนลูปเพื่อเปรียบเทียบความกว้างของคำกับความกว้างของสี่เหลี่ยมด้วยฟังก์ชั่น MeasureString() ถ้ายังกว้างกว่าก็จะลดขนาดของตัวอักษรลงมาเรื่อยๆ เมื่อได้ขนาดที่เหมาะสมแล้วจึงจัดวางให้อยู่กลางภาพโดยกำหนดให้ StringFormat.Alignment และ StringFormat.LineAlignment เท่ากับ StringAlignment.Center

ต่อมาสร้าง Path ของฟ้อนท์ขึ้นตามข้อความที่ได้ จากนั้นบิดด้วยเมธอด Warp เพื่อให้ชุดตัวอักษรบิดไปจากแนวระนาบ จากนั้นจึงวาดตัวอักษรลงไปบนสี่เหลี่ยมที่เราสร้างขึ้นในตอนแรก ระบายลวดลายลงบนตัวอักษรเพื่อทำให้โปรแกรมสแปมเมอร์อ่านได้ยากขึ้น

อันที่จริงเมื่อถึงขั้นตอนนี้กราฟิกที่เราสร้างขึ้นก็เรียกว่าใช้งานได้แล้ว แต่หากเราจะเพิ่มลูกเล่นเข้าไปเพื่อให้อ่านยากขึ้นอีกก็ทำได้ เช่น การวาดจุดแบบสุ่มลงไปตามตำแหน่งต่างๆ เป็นต้น

ขั้นตอนสุดท้ายคือการ Dispose ออปเจ็คต์ที่ไม่ใช้แล้วเพื่อคืน Resource กลับสู่ระบบ และนำ Bitmap ที่ได้ไปเก็บไว้ใน Image Property ของคลาสเป็นอันจบกระบวนการ

รูปที่ 3

รูปที่ 3: ผลสำเร็จของรูปจากคลาส CaptchaImage

บทสรุป

CAPTCHA เป็นวิธีการง่ายๆที่จะใช้ป้องกันการสแปมข้อความที่ไม่พึงประสงค์ และยังได้รับการใช้งานอย่างเป็นสากล วิธีการง่ายๆที่ใช้ในการสร้าง CAPTCHA ด้วย ASP.Net คือการสร้างและเรียกใช้ไฟล์ .aspx ที่คืนค่ากลับมาเป็นรูปภาพ แล้วนำข้อความที่ได้จากรูปภาพนั้นมาเปรียบเทียบกับสิ่งที่ผู้ใช้ป้อนเข้ามา แล้วจึงอนุญาตให้ผู้ใช้ทำงานในขั้นตอนอื่นต่อไป อย่างไรก็ดียังมีวิธีการอื่นๆอีกมากที่ใช้ป้องกันการโพสต์ข้อความขยะเหล่านี้ เช่น การกรองคำ (Filtering) หรือ ReverseDOS ซึ่งเป็นการดักจับพฤติกรรมการโพสต์ข้อความที่ผิดปรกติเป็นต้น แม้จะมีระบบการป้องกันที่ดีสักเพียงใด สิ่งที่นักพัฒนาและเจ้าของเว็บไซต์ปรารถนาเป็นอย่างยิ่งนั่นก็คือ การไม่พบข้อความขยะในระบบเลย ถึงแม้จะไม่มีการป้องกันใดๆนั่นเอง

Filed under: ,
 

เดก said:

ขอบคุณครับ

October 15, 2008 5:51 PM
 

supamit said:

ขอบคุณมากครับ  ช่วยผมได้ทันเวลาพอดี

December 31, 2008 5:37 PM

Leave a Comment

(required)  
(optional)
(required)  
Add