Dev (Back & Front)ARTIGO

Resolvendo dois problemas num só patch

Nos últimos meses, na empresa onde trabalho, estive um pouco atarefado com problemas de invasão do tipo SQLSQL64 conteúdosSQL Server – Como evitar SQL Injection?Data · mai 2019Azure SQL DB Managed InstanceData · abr 2019SQL Server – Como evitar SQL Injection? Pare de utilizar Query Dinâmica como EXEC(@Query)Data · abr 2019Ver tudo em Data Injection. Eu já tinha avisado meus superiores quando a vulnerabilidade do sistema que estava em utilização, porém, minhas sugestões para tornar o sistema mais seguro, só foram colocadas em prática quando o pesadelo virou realidade. A partir de então, o aspecto segurança passou a ser visto com mais atenção.

Após ganhar algumas horas em pesquisa sobre SQL Injection, descobri que o principal fator que possibilita o sucesso de um ataque deste tipo é a famosa técnica que a grande maioria de administradores inexperientes conhece, chamada NNF (next, next, finish). Achou engraçado? Mas é isso mesmo. A pessoa instala um servidor com as configurações padrão e logo disponibiliza este servidor em produção sem aplicar nenhum procedimento de segurança. Infelizmente isso é o que mais acontece e aconteceu comigo (não sou administrador de redes nem especialista em segurança, mas pra variar, em TI é sempre bom conhecer um pouco de tudo).

A instalação padrão de um servidor IIS exibe os erros HTTP 500;100 para o usuário que acessa um site. Esta configuração é tudo que um cracker precisa para desenvolver seu código malicioso. As formas mais comuns, através de formulários e até mesmo query strings, propositalmente o invasor vai provocando erros no código que fornecem as informações que ele precisa.

Sendo assim a melhor forma de tentar impedir o sucesso desse tipo de ataque é não exibir os erros http 500;100. Então você cria uma página de erro personalizada e direciona o erro para página criada na guia Http Custom Errors das propriedades do site.

Esta não é a solução definitiva, porém, somente esta ação aparentemente insignificante, reduz drasticamente a possibilidade de sucesso de um SQL Injection. Quer saber? Muito raramente alguém faz isso (com a exceção de empresas especializadas no assunto, ou empresas que foram vítimas de ataques).

Outra medida a ser tomada, e não menos importante, é a correção das falhas de segurança do código que em conjunto com os erros exibidos na tela, permitiram o sucesso da invasão. Mas isso eu vou mostrar falar em outro artigo.

Acontece que com a customização do erro, eu eliminei a única forma de debug que eu e os outros desenvolvedores que trabalham comigo tínhamos. Nesta hora de desespero total, eu percebi que ainda existia uma luz no fim do túnel: estou falando do comando Server.GetLastError().

Com esse comando é possível criar uma página de erro personalizada. Só que mostrar os erros na tela voltaria a fornecer informações preciosas aos invasores. Então tive a idéia de enviar os erros por e-mail. Pensei em algumas informações que os desenvolvedores precisam saber para resolver o problema e desenvolvi um script que reúne as seguintes informações: url de origem, url de destino, página do erro, código e descrição do erro, variáveis de formulário (post), variáveis de query string (get), variáveis de sessão do usuário e todos as ServerVariables. Adicionei este script a pagina de erro customizado e, acreditem ou não, uma série de melhorias começaram a acontecer:

  • os desenvolvedores passaram a ter informações antes mesmo de o usuário abrir um chamado junto à equipe de suporte;
  • conhecimento de bugs no sistema, antes desconhecidos;
  • redução do número de abertura de chamados;
  • usuários mais satisfeitos com o sistema;
  • um sistema mais estável e seguro (porque as tentativas de invasão mal sucedidas também chegam por e-mail), entre outras coisas;

A principal desvantagem é a quantidade de e-mails recebidos inicialmente, porém, na medida que os problemas são solucionados, obviamente os e-mails diminuem.

Os famosos robôs de indexação de páginas (os crawlers como Googlebot, msnbot…), na tentativa de atualizar seu cache de página antigas aumentavam bastante o número de e-mails. Por isso existe no script um filtro dos principais robôs que acessam as páginas do meu sistema.

Segue o código do script que salvei com o nome my500.asp (esta página deve ser configurada no IIS) :

my500.asp


<%LANGUAGE="VBSCRIPT" CODEPAGE="1252"%>
<%
' TRATAMENTO DE ERROS
Option Explicit
On Error Resume Next
Response.Clear
Dim objError, sKey, Texto
Set objError = Server.GetLastError()

' EXPRESSÃO REGULAR PARA IDENTIFICAR SE O AGENTE É UM ROBÔ (CRAWLERs)
Dim reBots
Set reBots = new RegExp
reBots.IgnoreCase = True
reBots.Global = True
reBots.Pattern = "(msnbot|Slurp|Googlebot)"
Texto = Request.ServerVariables("HTTP_USER_AGENT")

' SE NÃO FOR UM ROBÔ, ENVIA O E-MAIL
If Not reBots.Test( Texto ) Then

	' LÊ O ARQUIVO CORPO DO E-MAIL (MODELO)
	Dim fso, HtmlFile, HtmlText
	Set fso 	 = Server.CreateObject("Scripting.FileSystemObject")
	Set HtmlFile = fso.OpenTextFile(Server.MapPath("/erros/my500.html"), 1, False)
	HtmlText 	 = HtmlFile.ReadAll
	HtmlFile.Close
	Set HtmlFile = Nothing
	Set fso 	 = Nothing
	
	' SUBSTITUI VARIÁVEIS DO CORPO DO E-MAIL
	Dim re, sd
	Set sd = Server.CreateObject("Scripting.Dictionary")
	Set re = new RegExp
	re.IgnoreCase = True
	re.Global	  = True
	
	' ARRAY DE VALORES QUE SERÃO ADICIONADOS AO CORPO DO TEXTO
	Texto = "http://" & Request.ServerVariables("HTTP_HOST") & Request.ServerVariables("URL")
	If Len(Trim( Request.ServerVariables("QUERY_STRING") )) <> 0 Then Texto = Texto  "?"  Request.ServerVariables("QUERY_STRING")				
	sd.Add "host", Texto
	
	Texto = Request.ServerVariables("HTTP_REFERER")
	If Len(Trim(Texto)) = 0 Then Texto = "Acesso Direto"
	sd.Add "referer", Texto
	
	sd.Add "iis.err", 	objError.ASPCode
	sd.Add "com.err", 	objError.Number & " (0x" & Hex(objError.Number) & ")"
	sd.Add "err.src", 	objError.Source
	sd.Add "filename",	objError.File
	sd.Add "err.line", 	objError.Line
	sd.Add "err.desc", 	objError.Description
	sd.Add "asp.desc", 	objError.ASPDescription
	
	Texto = ""
	For Each sKey In Request.QueryString 
		Texto = Texto & sKey & " = " & Request.QueryString(sKey) & "<br />" & VbCrLf
	Next
	sd.Add "request.querystring", Texto
	
	Texto = ""
	For Each sKey In Request.Form 
		Texto = Texto & sKey & " = " & Request.Form(sKey) & "<br />"  VbCrLf
	Next
	sd.Add "request.form", Texto
	
	Texto = ""
	For Each sKey In Request.ServerVariables
		Texto = Texto & sKey & " = " & Request.ServerVariables(sKey) & "<br />"  VbCrLf
	Next
	sd.Add "Request.ServerVariables", Texto
	
	Texto = ""
	For Each sKey In Session.Contents 
		Texto = Texto & sKey & " = " & Session.Contents(sKey) & "<br />" & VbCrLf
	Next
	sd.Add "sessions", Texto
	
	' SUBSTITUI AS VARIÁVEIS NO CORPO DO E-MAIL QUE SERÁ ENVIADO
	For Each sKey In sd
		re.Pattern 	= "\{\{" & sKey & "\}\}"
		HtmlText 	= re.Replace( HtmlText, sd( sKey ) )
	Next
	
	sd.RemoveAll
	Set sd = Nothing
	Set re = Nothing
	
	' ENVIA UM E-MAIL PARA O ADMINISTRADOR DO SISTEMA
	Dim objCDOSYSMail
	Dim objCDOSYSCon
	
	Set objCDOSYSMail = Server.CreateObject("CDO.Message")
	Set objCDOSYSCon  = Server.CreateObject("CDO.Configuration")
	
	objCDOSYSMail.From 		= "email_from@seusite.com.br"
	objCDOSYSMail.To   		= "dev@seusite.com.br"
	objCDOSYSMail.Subject  	= "Erro ASP 500"
	objCDOSYSMail.HtmlBody 	= HtmlText
	objCDOSYSMail.Send
	
	' DESTRÓI OS OBJETOS
	Set objCDOSYSMail = Nothing
	Set objCDOSYSCon = Nothing
	
End If

' DESTRÓI OS OBJETOS
Set reBots   = Nothing
Set objError = Nothing
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Erro ASP 500</title>
</head>
<body>
Mensagem de erro que você achar melhor.
</body>
</html>

O script utiliza uma página modelo (my500.htmlHTML45 conteúdosA importância do HTML e CSS para quem trabalha com UI Design e Design SystemProduto & UX · dez 2024Como hostear seu site HTML gratuitamente com GitHub PagesDev (Back & Front) · jun 2025SQL Server – Como criar um versionamento de código das suas Stored Procedures em HTML e com comentários da alteraçãoData · nov 2020Ver tudo em Dev (Back & Front) ) com variáveis que são substituidas pelo devido conteúdo.

Segue o código da página my500.html:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Erro ASP 500</title>
<style>
body  { FONT-FAMILY: Arial; FONT-SIZE: 10pt; BACKGROUND: ffffff; COLOR: 000000; MARGIN: 15px; }
H2    { FONT-SIZE: 16pt; COLOR: ff0000; }
TABLE { BACKGROUND: FFF; PADDING: 5px; }
</style>
</head>
<body>
<h2 align="center">Erro ASP 500</h2>
<p align="center">Paacute;gina de origem: {{referer}}<br />
Paacute;gina com erro:  {{host}}</p>
<div align="center"><center>
<table width="90" border="0" cellpadding="2" cellspacing="2">
  <tr>
    <th width="180" align="left" valign="top" nowrap>Nuacute;mero do Erro IIS</th>
    <td align="left" valign="top">{{iis.err}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap>Nuacute;mero do Erro COM </th>
    <td align="left" valign="top">{{com.err}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap>Coacute;digo Fonte do erro </th>
    <td align="left" valign="top">{{err.src}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap>Nome do Arquivo </th>
    <td align="left" valign="top">{{filename}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap> Linha </th>
    <td align="left" valign="top">{{err.line}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap>Breve Descricao </th>
    <td align="left" valign="top">{{err.desc}}</td>
  </tr>
  <tr>
    <th width="180" align="left" valign="top" nowrap>Descriccedil;atilde;o Completa </th>
    <td align="left" valign="top">{{asp.desc}}</td>
  </tr>
  <tr>
    <th colspan="2" align="left" valign="top" nowrap>nbsp;</th>
  </tr>
  </table>
  <table width="90" border="0" cellpadding="2" cellspacing="2">
  <tr>
    <th colspan="2" align="left" valign="top" nowrap>Query String</th>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap> 
	{{request.querystring}}</td>
  </tr>
     <tr>
    <th colspan="2" align="left" valign="top" nowrap>nbsp;</th>
  </tr>
  <tr>
    <th colspan="2" align="left" valign="top" nowrap>Formulaacute;rio </th>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap> {{request.form}}</td>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap>nbsp;</td>
  </tr>
  <tr>
    <th colspan="2" align="left" valign="top" nowrap>Variaacute;veis de Sessatilde;o </th>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap>{{sessions}}</td>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap>nbsp;</td>
  </tr>
  <tr>
    <th colspan="2" align="left" valign="top" nowrap>Variaacute;veis do Servidor </th>
  </tr>
  <tr>
    <td colspan="2" align="left" valign="top" nowrap>{{Request.ServerVariables}}</td>
  </tr>
</table>
</center>
</div>
</body>
</html>

Espero que gostem e que o scirpt ajude a muitos, porque a mim tem ajudado bastante.

Abraços.

é profissional graduado pela Universidade Ibirapuera, desenvolvedor web desde 2002. Trabalhou por quatros anos na maior empresa de eventos (da américa latina) no setor de alimentos. Atualmente é analista programador em uma universidade. Trabalha com programação PHP, ASP, Webstandards, AJAX, MSSQL, MySql e é um grande entusiasta do mundo open source.

Ver perfil

Mais de Wesley De Menezes Flor