ASP .NET - Usando validação por imagem - CAPTCHA
Geralmente você encontra este recurso em páginas de enquete ou listas de discussão onde o usuário deve votar , dar a sua opinião ou emitir um comentário e antes de enviar deve informar o código com caracteres gerados no formato de figura distorcida da página. O objetivo é ter certeza de que não é uma máquina quem esta enviando a requisição.
Estas imagens distorcidas envolvem a técnica conhecida como CAPTCHA. Um CAPTCHA apresenta caracteres tão distorcidos que quase nenhum programa seria capaz de interpretá-los e decifrá-los de maneira automática. Teoricamente, só mesmo um humano conseguiria entendê-lo e digitar a seqüência correta, comprovando que é um humano e não um programa malicioso , spam, etc.
Veja a abaixo um trecho da definição da Wikipédia - http://pt.wikipedia.org/wiki/CAPTCHA
CAPTCHA é um acrônimo de - Completely Automated Public Turing test to tell Computers and Humans Apart - e envolve um computador (um servidor) que pede que um usuário termine um teste. Como os computadores são incapazes de resolver o CAPTCHA, todo usuário que incorpora uma solução correta é presumidamente humano. O termo foi inventado em 2000 por Luis von Ahn, Manuel Blum , Nicholas J. Hopper e por John Langford.
Um tipo comum de CAPTCHA requer que o usuário identifique as letras de uma imagem distorcida, às vezes com a adição de uma seqüência obscurecida das letras ou dos dígitos que apareça na tela. Como o teste é administrado por um computador, em contraste ao teste padrão de Turing que é administrado por um ser humano, é descrito às vezes como um "teste reverso de Turing".
Abaixo temos exemplos de imagens CAPTCHA:
Este CAPTCHA de "smwm" distorce a mensagem para evitar a interpretação automática por computadores. Entretanto, programas foram desenvolvidos para ler este tipo de CAPTCHA[1]. |
CAPTCHA mais moderno. Melhora tentando criar um fundo distorcido e uns níveis elevados de entortar no texto, este CAPTCHA focaliza em fazer a segmentação e dificulta adicionando uma linha angular. |
O CAPTCHA é usado para evitar ataques de robos ou bots (o termo bots vem de robots, robôs em inglês), programinhas maliciosos que automatizam operações repetitivas. Sem os captchas, esses bots seriam capazes de simular um humano digitando informações aleatórias de modo a criar centenas ou até milhares de requisições em poucas horas.
Após esta introdução vou mostrar uma forma de implementar a validação por imagens em páginas ASP .NET.
O cenário hipotético será simular uma votação onde o usuário deve selecionar uma opção e clicar no botão votar. Apenas para ilustrar vamos propor a votação sobre um tema bem atual: Você concorda com a liberação das pesquisas usando células tronco ?
Abra o Visual Web Developer 2008 Express Edition e crie um novo web site chamado CaptchaNet usando a linguagem VB .NET usando o template ASP .NET Web site;
Selecione a página Default.aspx e a partir do menu Table selecione Insert Table para incluir uma tabela com 7 linhas e 1 coluna na página:
Vamos criar um leiaute bem simples contendo a pergunta sobre o tema e :
Agora vamos incluir uma classe no web site; menu WebSite selecione Add New Item e em Templates selecione Class informando o nome Captcha.vb;
O arquivo será incluído na pasta App_Code. Agora digite o código abaixo na classe;
Imports Microsoft.VisualBasicImports SystemImports System.DrawingImports System.Drawing.Drawing2DImports System.Drawing.ImagingImports System.Drawing.Text
Namespace Captcha
''' <summary> ''' Summary description for CaptchaImage. ''' </summary>Public Class CaptchaImage ' Public properties (all read-only). Public ReadOnly Property Text() As String Get Return Me.m_textEnd Get End PropertyPublic ReadOnly Property Image() As Bitmap Get Return Me.m_imageEnd Get End PropertyPublic ReadOnly Property Width() As Integer Get Return Me.m_widthEnd Get End PropertyPublic ReadOnly Property Height() As Integer Get Return Me.m_height End Get End Property' Internal properties. Private m_text As String Private m_width As Integer Private m_height As Integer Private familyName As String Private m_image As Bitmap
' For generating random numbers. Private random As New Random()' ==================================================================== ' Initializes a new instance of the CaptchaImage class using the ' specified text, width and height. ' ==================================================================== Public Sub New(ByVal s As String, ByVal width As Integer, ByVal height As Integer)Me.m_text = s Me.SetDimensions(width, height) Me.GeraImagem() End Sub ' ==================================================================== ' Initializes a new instance of the CaptchaImage class using the ' specified text, width, height and font family. ' ==================================================================== Public Sub New(ByVal s As String, ByVal width As Integer, ByVal height As Integer, ByVal familyName As String)Me.m_text = s Me.SetDimensions(width, height) Me.SetFamilyName(familyName) Me.GeraImagem() End Sub Protected Overrides Sub Finalize() Try ' ==================================================================== ' This member overrides Object.Finalize. ' ====================================================================Dispose( False)Finally MyBase.Finalize()End Try End Sub' ==================================================================== ' Releases all resources used by this object. ' ==================================================================== Public Sub Dispose()GC.SuppressFinalize(Me) Me.Dispose(True) End Sub ' ==================================================================== ' Custom Dispose method to clean up unmanaged resources. ' ==================================================================== Protected Overridable Sub Dispose(ByVal disposing As Boolean)If disposing Then Me.m_image.Dispose()' Dispose of the bitmap. End If End Sub' ==================================================================== ' Sets the image width and height. ' ==================================================================== Private Sub SetDimensions(ByVal width As Integer, ByVal height As Integer)' Check the width and height. If width <= 0 Then Throw New ArgumentOutOfRangeException("width", width, "Argument out of range, must be greater than zero.")
End
If End If Me.m_width = width Me.m_height = height End Sub ' ==================================================================== ' Sets the font used for the image text. ' ==================================================================== Private Sub SetFamilyName(ByVal familyName As String)' If the named font is not installed, default to a system font. TryDim font As New Font(Me.familyName, 12.0F) Me.familyName = familyName font.Dispose() Catch ex As Exception Me.familyName = System.Drawing.FontFamily.GenericSerif.Name End Try End Sub' ==================================================================== ' Cria uma imagem bitmap ' ==================================================================== Private Sub GeraImagem()
' Create a new 32-bit bitmap image. Dim bitmap As New Bitmap(Me.m_width, Me.m_height, PixelFormat.Format32bppArgb)
' Create a graphics object for drawing. Dim g As Graphics = Graphics.FromImage(bitmap)g.SmoothingMode = SmoothingMode.AntiAlias Dim rect As New Rectangle(0, 0, Me.m_width, Me.m_height)
' Fill in the background. Dim hatchBrush As New HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White)g.FillRectangle(hatchBrush, rect)
' Set up the text font. Dim size As SizeFDim fontSize As Single = rect.Height + 1 Dim font As Font
' Adjust the font size until the text fits within the image. DofontSize -= 1 font = New Font(Me.familyName, fontSize, FontStyle.Bold)size = g.MeasureString(Me.m_text, font) Loop While size.Width > rect.Width
' Set up the text format. Dim format As New StringFormat()format.Alignment = StringAlignment.Center format.LineAlignment = StringAlignment.Center
' Create a path using the text and warp it randomly. Dim path As New GraphicsPath()path.AddString(Me.m_text, font.FontFamily, CInt(font.Style), font.Size, rect, format) Dim v As Single = 4.0F Dim points As PointF() = {New PointF(Me.random.[Next](rect.Width) / v, Me.random.[Next](rect.Height) / v), New PointF(rect.Width - Me.random.[Next](rect.Width) / v, Me.random.[Next](rect.Height) / v), New PointF(Me.random.[Next](rect.Width) / v, rect.Height - Me.random.[Next](rect.Height) / v), New PointF(rect.Width - Me.random.[Next](rect.Width) / v, rect.Height - Me.random.[Next](rect.Height) / v)} Dim matrix As New Matrix() matrix.Translate(0.0F, 0.0F) path.Warp(points, rect, matrix, WarpMode.Perspective, 0.0F)
' Draw the text. hatchBrush = New HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray)g.FillPath(hatchBrush, path)
' Add some random noise. Dim m As Integer = Math.Max(rect.Width, rect.Height)For i As Integer = 0 To CInt((rect.Width * rect.Height / 30.0F)) - 1 Dim x As Integer = Me.random.[Next](rect.Width) Dim y As Integer = Me.random.[Next](rect.Height) Dim w As Integer = Me.random.[Next](m / 50) Dim h As Integer = Me.random.[Next](m / 50) g.FillEllipse(hatchBrush, x, y, w, h) Next ' Clean up. font.Dispose() hatchBrush.Dispose() g.Dispose() ' Set the image. Me.m_image = bitmapEnd Sub End ClassEnd Namespace
|
O código tem o objetivo de gerar uma imagem bitmap.
Vamos incluir uma nova página chamada JpegImage.aspx no web site através do menu Website opção Add new Item,e em Templates selecione Web Form e informe o nome conforme figura abaixo;
No code-behind desta página , arquivo JpegImage.aspx.vb , inclua o código abaixo na página que irá gerar a imagem usando a classe criada no arquivo Captcha.vb;
Imports System.DrawingImports System.Drawing.Imaging
Partial Class JpegImageInherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' Cria uma imagem CAPTCHA usando o texto armazenado na sessão Dim ci As New Captcha.CaptchaImage(Me.Session("CaptchaImageText").ToString(), 200, 50, "Macoratti.net")
' altera a resposta do header para a saida de imagem JPEG Me.Response.Clear()Me.Response.ContentType = "image/jpeg" ' Escreve a imagem no stream de resposta no formato JPEG ci.Image.Save( Me.Response.OutputStream, ImageFormat.Jpeg)
' libera o objeto imagem CAPTCHA. ci.Dispose() End Sub End Class
|
A imagem é gerada usando o texto aleatório armazenado na sessão : Session("CaptchaImageText") e liberada no formato JPEG.
O texto aleatório será gerado na página onde a validação deve ser feita , no nosso caso a página Default.aspx.
Vejamos agora como deve ficar o código do arquivo Default.aspx.vb:
Partial Class _DefaultInherits System.Web.UI.Page
' cria um codigo aleatorio que sera arrmazenado na sessão Private random As New Random()
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 'Verifica se é a primeira execução da página If Page.IsPostBack = False Then Me.Session("CaptchaImageText") = GeraCodigoAleatorio() Else verificaCaptcha() End If End SubPrivate Function GeraCodigoAleatorio() As String ' Retorna uma string de sete digitos aleatorios Dim s As String = "" For i As Integer = 0 To 6 s = [String].Concat(s, Me.random.[Next](10).ToString()) Next Return sEnd Function Private Function verificaCaptcha() As Boolean If Me.txtCodigoCaptcha.Text = Me.Session("CaptchaImageText").ToString() Then ' exibe uma mensagem de aviso Me.lblMensagem.Text = "C¢digo Correto." Return True Else 'exibe uma mensagem de erro Me.lblMensagem.Text = "C¢digo Incorreto." ' ' limpa a entra e cria um novo codigo aleaorio Me.txtCodigoCaptcha.Text = "" Me.Session("CaptchaImageText") = GeraCodigoAleatorio() Return False End If End FunctionProtected Sub btnEnviar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnEnviar.Click If verificaCaptcha() Then Response.Redirect( "ok.aspx")Exit Sub ElseExit Sub End If End Sub End Class |
Vamos entender o que esta sendo feito:
O código - Private random As New Random() - cria um código aleatório que será armazenado na sessão.
No evento Load do formulário temos que na primeira vez é gerado um código aleatório e colocado na sessão e nas demais vezes executamos a função verificaCaptcha();
'Verifica se é a primeira execução da página
If Page.IsPostBack = False ThenMe.Session("CaptchaImageText") = GeraCodigoAleatorio()
Else
verificaCaptcha()
End If
A função GeraCodigoAleatorio() usa o randômico gerado e retorna um string de 7 dígitos aleatórios;
Private Function GeraCodigoAleatorio() As String
s = [String].Concat(s, Me.random.[Next](10).ToString())
Next
Return sEnd Function
A função verificaCaptcha() ir verificar se o código digitado na caixa de texto - txtCodigoCaptcha - é igual ao gerado na sessão se não for igual exibe uma mensagem , limpa o TextBox e gera outro código na sessão.
Private Function verificaCaptcha() As Boolean If Me.txtCodigoCaptcha.Text = Me.Session("CaptchaImageText").ToString() Then ' exibe uma mensagem de aviso
Me.lblMensagem.Text = "C¢digo Correto."
Return True Else
'exibe uma mensagem de erro
Me.lblMensagem.Text = "C¢digo Incorreto." ' ' limpa a entra e cria um novo codigo aleaorio
Me.txtCodigoCaptcha.Text = ""
Me.Session("CaptchaImageText") = GeraCodigoAleatorio()
Return False
End If End Function
E como a imagem é gerada na página ???
Note que introduzimos o controle : <img src="JpegImage.aspx" />
Neste controle a imagem é obtida como retorno da página JpegImage.aspx que gera a imagem a partir do texto na sessão usando a classe Captcha que criamos.
Falta apenas criar uma página chamada ok.aspx para a qual o usuário será direcionado caso o código esteja correto.
No menu WebSite selecione Add New Item e inclua um novo WebForm com o nome de ok.aspx a seguir defina o seguinte leiaute para a página:
O código para validação e verificação do Captcha é feito no botão Enviar. No seu evento Click coloque o código:
Protected Sub btnEnviar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnEnviar.ClickIf verificaCaptcha() Then Response.Redirect( "ok.aspx")Exit Sub ElseExit Sub End If End Sub |
Executando a página iremos obter:
Este artigo teve o objetivo de introduzir o assunto apresentando uma forma de implementar a validação por imagens em páginas ASP .NET e não deve ser tomado como referência exclusiva. Se você pretende implementar a técnica em um site de produção deverá usar um código mais robusto e pesquisar melhores opções existentes.
Lembrando que usar CAPTCHA por si só não evita um ataque, visto que já existem robôs que quebram o CAPTCHA usando algoritmos complexos e técnicas de reaproveitamento da "session-ID" de um captcha conhecido.
Veja este texto publicado no GLOBO - Informática por Carlos Alberto Teixeira :
Hoje em dia, encontrar um captcha não é nada difícil. Só que já tem uma rapaziada derrotando captcha. Acredite, tem sim. São brilhantes esses caras. Eles estão construindo bots que capturam um captcha original em um site X, apresentam-no a um humano num site diferente Y, em outro contexto, registram a resposta da criatura e submetem-na de volta ao campo digitado no site X de onde capturaram a figura, transpondo a barreira de segurança e ganhando acesso a seja lá o que for que estão querendo acessar.
Em geral, esses gênios usam como site Y páginas de pornografia, que os tarados virtuais acessam em busca de material para seus devaneios. Assim, fingindo que é uma barreira real, o bot apresenta ao ávido internauta o captcha capturado no site X. O camarada vai lá e digita sua interpretação da figura. O bot pega os caracteres digitados no site pornô Y, que está sob seu controle, e "digita" os mesmos caracteres no site X. E pronto, mais uma vitória da inteligência a serviço do mal.
Então todo o cuidado é pouco...
Até o próximo artigo ASP .NET.
Veja o projeto funcionando aqui : http://macoratti.net/captcha
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? |
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Super DVD C# - Recursos de aprendizagens e vídeo aulas para C#
Curso Fundamentos da Programação Orientada a Objetos com VB .NET
A CAPTCHA Server Control for ASP.NET - http://www.codeproject.com/KB/custom-controls/CaptchaControl.aspx