Sua aplicação web é segura?
SEGURANÇA
Aplicação web protegida
Aplicações web oferecem grandes riscos à segurança. Aprenda a
proteger todos os elementos dessa complexa equação.
por Celio de Jesus Santos e Cloves Ferreira Junior
A
construção de sites dinâmicos se tornou muito comum
com o decorrer dos tempos,
trazendo inúmeras vantagens para as
empresas e sendo utilizada como uma
poderosa ferramenta de marketing.
Porém, isso pode se converter em
um problema caso o site ou a aplicação não seja desenvolvido com as
devidas preocupações relacionadas à
segurança da informação. Ao se tratar
de algo voltado para a Internet, esse
site estará exposto para quem quiser
acessá-lo, ou seja, se torna público
e sua segurança é colocada à prova
por qualquer pessoa que queira testar
o nível de proteção, independentemente de sua índole.
Todas as linguagens de programação têm suas particularidades,
mas no decorrer deste artigo trabalharemos com a linguagem PHP,
pois é a base da maioria dos sites
existentes atualmente.
Ataques de sessão
A definição para este tipo de problema
está relacionada à má implementação
das conexões realizadas pelos usuários a uma determinada aplicação
que necessita rastrear as requisições
destes ou tomar decisões com base
nas credenciais de autenticação [1].
66
Os danos causados por esse tipo
de ataque vão desde a elevação de
privilégios até o roubo de informações
de usuários e o comprometimento
dos dados da aplicação uma vez que
o atacante consiga elevar os privilégios de um usuário vítima e obtenha
acesso por meio de um usuário com
privilégios administrativos.
Como exemplo, poderíamos utilizar um cookie, um campo oculto
etc., mas vamos partir de uma página
que recebe pela URL as credenciais
de um usuário já autenticado:
http://site.com.br/pagina.
php?usuario=bob&nivel=1
A listagem 1 ilustra como seria o
código-fonte de pagina.php que foi
codificado sem a preocupação com
a alteração indesejável dos dados
por um usuário que detém algum
conhecimento sobre aplicações web.
Note que este código recebe os
dados vindos do usuário e implementa uma consulta em uma base
de dados para uma possível decisão
futura de acordo com o retorno da
consulta. Isso significa que se aplicarmos os truques que caracterizam
esse tipo de ataque – isto é, alterar
as credenciais de um usuário válido
por meio da URL –, conseguiríamos sucesso:
http://site.com.br/pagina.
php?usuario=alice&nivel=1
Com isso, o usuário da aplicação
conseguiria visualizar uma página
montada dinamicamente, mas que
pertence a outro usuário da aplicação (no caso, alice). A partir desse
ponto, ele poderia fazer tudo o que
a aplicação permite ao usuário alice.
Para evitar esse tipo de problema, o ideal é não armazenar essas
credenciais de usuário no lado do
cliente, mas em um objeto session
no lado servidor. Para implementar essa solução nesse ambiente de
exemplo, bastaria armazenarmos um
hash das credenciais do usuário em
um objeto session no lado servidor
no momento da autenticação e em
todas as páginas que necessitassem
dessas credenciais. Antes de executar
qualquer ação com as credenciais fornecidas ao programa atual, o servidor
faria uma comparação entre o hash
informado e aquele armazenado no
lado servidor.
Vejamos na listagem 2 como podemos implementar esta solução.
Trata-se de um trecho do código do
http://www.linuxmagazine.com.br
Aplicações web | SEGURANÇA
programa autentica.php, que cria o
hash das credenciais com a função
md5() do PHP no momento da autenticação e a armazena em uma
variável de sessão (objeto SESSION).
Na linha 1 da listagem 2, iniciamos
o objeto de sessão. Na sequência,
verificamos se houve sucesso na
autenticação do usuário e, em caso
positivo, o hash é armazenado em
uma variável da sessão.
Agora vamos verificar como ficaria a codificação da validação das
credenciais informadas ao programa
pagina.php na listagem 3.
Esse código implementa uma validação com os dados recebidos por
meio da comparação dos hashes. Com
o sucesso da validação, é executado
o restante do script; caso contrário,
pode-se informar o erro ao usuário
ou redirecioná-lo para uma nova
tentativa de autenticação. É importante implementar outras alternativas, como a proteção dos parâmetros
passados via URL, a criptografia das
informações de tokens etc.
Cross-site
scripting (XSS)
Ataques do tipo XSS, ou Cross-site
scripting (scripts entre sites), acontecem quando a aplicação recebe dados do usuário e os envia de volta ao
cliente sem as devidas validações para
sua correta exibição no navegador.
A técnica do XSS se caracteriza
pela inserção de tags HTML, em
particular a tag <script> [1]. Quando a aplicação executa a tag no navegador cliente em vez de apenas
imprimir este conteúdo, os dados
da sessão – incluindo informações
potencialmente sensíveis do usuário – podem ser enviados para qualquer destino sem que o servidor ou
o cliente percebam.
Esta vulnerabilidade em uma
aplicação pode causar sérios danos para seu usuário, uma vez que
o foco não é acessar ou manipular
Linux Magazine #60 | Novembro de 2009
dados da aplicação como no caso
da injeção de SQL, mas explorar
vulnerabilidades do próprio navegador do usuário com a execução
de scripts maliciosos em JavaScript,
VBScript, ActiveX etc. Outro problema potencial é o sequestro de
sessão, dependendo de como forem
armazenadas as credenciais de um
usuário autenticado.
O teste mais simples para esta vulnerabilidade é a inserção da string a
seguir em uma página parametrizada
por meio de uma variável, que no
nosso exemplo é a variável id:
http://site.com.br/pagina.
php?id=<script>alert(‘XSS’);
</script>
O código vulnerável que poderia
receber uma string como esta é:
<?php
//pagina.php
print $_REQUEST[“id”];
?>
Qualquer página com um código semelhante a este está vulnerável, pois os dados são obtidos
e impressos na tela sem qualquer
verificação, ou seja, acreditamos
ingenuamente que o usuário sempre passará dados confiáveis.
Vamos imaginar um mural de
recados que armazene os dados em
uma tabela de banco de dados ou até
mesmo em um arquivo texto. Suponhamos que o código desse mural
aceite a seguinte string a seguir no
lugar do texto que seria o recado:
<script>for(i=0%3bi<10%3bi%2b%2b)
{alert(i)%3b}</script>
O problema causado por essa
string seria simples, mas emitiria dez
mensagens de alerta toda vez que a
página fosse carregada, como mostra
a figura 1. Contudo a gravidade do
problema estaria ligada à criatividade
da pessoa que a fizer.
Para corrigir esse problema, seria
preciso alterar o arquivo pagina.php
Listagem 1: Página insegura
01
02
03
04
05
06
07
08
09
10
11
12
<?php
/*Dados do formulário*/
$usuario = $_REQUEST[“usuario”];
$nivel = (int)$_REQUEST[“nivel”];
/*montando a Query*/
$sql =”SELECT * FROM tabela
WHERE usuario = ‘”.$usuario.”’ AND
nivel = “.$nivel;
$rs = mysql_query($sql);
Listagem 2: Segurança na autenticação
01 <?php
02 /*autentica.php*/
03 session_start();
...
16 /*Sucesso na autenticação*/
17 if ($autenticado){
18 $_SESSION[“hash”]=md5($usuario.””.$nivel);
19 }
20
21 ?>
67
SEGURANÇA | Aplicações web
:<?php
//pagina.php
print htmlentities($_
REQUEST[“id”],
ENT_QUOTES);
?>
e também o mural.php, responsável
por exibir o mural de recados:
<?php
//mural.php
.
.
.
print
htmlentities($dados[“recado”],
ENT_QUOTES);
?>
Esta solução foi utilizada com a
função do PHP que faz uma conversão dos dados para entidades HTML,
htmlentities(), mas também podemos utilizar outra função chamada
strip_tags(), ou até mesmo expressões regulares.
No caso do XSS, a aplicação deve
garantir que somente o seu próprio
código seja executado, impedindo
que os usuários insiram códigos arbitrários. Isso evita que a aplicação
tenha seu comportamento alterado,
o que pode prejudicar o acesso do
usuário à aplicação.
Falhas de autenticação
A autenticação de usuários é uma das
primeiras partes de uma aplicação
web a ser testada por alguém que deseja verificar seu nível de segurança.
Portanto, é fundamental usar códigos seguros – preocupe-se até com
os mínimos detalhes envolvidos no
ato do desenvolvimento.
Este problema envolve falhas
no mecanismo de autenticação
da aplicação, que por um motivo
ou outro não foi bem codificado
ou não recebeu a devida atenção
com relação à gerência da pós-autenticação, talvez até mesmo por
imaturidade do desenvolvedor. Os
danos causados por esse tipo de pro-
Listagem 3: Validação das credenciais
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
68
<?php
/*Iniciando a sessão*/
session_start();
/*Dados do formulário*/
$usuario = $_REQUEST[“usuario”];
$nivel= (int)$_REQUEST[“nivel”];
/*Obetendo os hashes atuais*/
$hash = md5($usuario.””.$nivel);
/*verifica se os hashes são iguais*/
if(strcmp($_SESSION[“hash”], $hash) == 0){
/*montando a Query*/
$sql = “SELECT * FROM tabela
WHERE usuario = ‘”.$usuario.”’ AND nivel = “.$nivel;
$rs = mysql_query($sql);
}
else {
/*requer autenticação novamente*/
header(“Locarion: login.php”);
}
?>
blema incluem o roubo de contas
de usuários, o que caracteriza a
violação de privacidade.
O primeiro cuidado que o desenvolvedor deve tomar para evitar
ataques de falha de autenticação
é garantir que a tela de login seja
acessada por meio de uma comunicação segura para que as credenciais
informadas pelo usuário não sejam
facilmente capturadas durante o transporte até o servidor web. A proteção
mais prática, nesse caso, é utilizar o
protocolo HTTPS para servir a página de autenticação.
Outro cuidado importante é o
uso de uma boa lógica para a programação do sistema de autenticação,
realizando as validações necessárias
para que somente sejam aceitos dados
relevantes para a aplicação, como
exemplifica a listagem 4.
Além disso, toda aplicação fornece
um link para permitir ao usuário encerrar sua sessão autenticada. Porém,
também é obrigatório garantir que, se
ele clicar somente no botão para fechar
a janela do navegador, em vez de usar
o link de encerramento da sessão, a
sessão seja completamente destruída
[2]. Caso isso não ocorra, é possível
que o próximo usuário que utilizar
a aplicação no mesmo computador
encontre a sessão já autenticada. Por
isso, a aplicação deve expirar a sessão
após um prazo determinado sem utilização para garantir que a sessão do
usuário não fique exposta.
O código abaixo (arquivo logoff.
php) realiza todas essas operações de
uma só vez:
<?php
//logof.php
unset($_SESSION);
?>
Um ponto importante que também está relacionado à autenticação
é o bloqueio da conta do usuário
em casos de múltiplas falhas de autenticação num intervalo pré-deter-
http://www.linuxmagazine.com.br
Aplicações web | SEGURANÇA
minado. Isso evita ataques de força
bruta, frequentemente ignorados
pelos desenvolvedores web, porém
extremamente perigosos.
Com relação à comunicação da
aplicação web com o usuário, é fundamental que este seja notificado
sobre qualquer incidente que ocorra
com relação à sua conta de usuário.
Os cuidados citados não dependem
da linguagem utilizada do lado servidor, mas do uso de alguns truques
para evitar esses problemas que estão
diretamente ligados à boa gerência
da sessão autenticada.
Servidor assegurado
Por se tratar da parte que fica exposta à Internet, o servidor web
também precisa estar protegido;
suas configurações devem fornecer apenas o necessário para que a
aplicação funcione.
Esse trabalho não cabe ao desenvolvedor, mas é necessário algum
conhecimento sobre o assunto, pois
a segurança da aplicação pode ser
comprometida caso seja explorada
alguma falha de segurança por parte do servidor web e vice-versa. Isso
significa que a segurança não deve
estar localizada somente no servidor
web ou somente na aplicação, mas
em ambos.
Figura 1Um “ataque” de exemplo seria a inclusão de código para exibir dez
avisos no navegador do cliente.
Os principais cuidados que devem
ser tomados no ato da configuração de
um servidor web são descritos a seguir.
Menor privilégio
O princípio do menor privilégio dita
que o serviço HTTP deve ser executado com uma conta do sistema
operacional que não tenha privilégios
de administrador, mas apenas os privilégios necessários para a execução
deste serviço.
Para isso, o correto é criarmos um
grupo de usuários com o nome do
serviço e um usuário com o mesmo nome – e evidentemente pertencente a esse grupo – no sistema
operacional com os privilégios mínimos. No caso do Apache, todas as
distribuições responsáveis já criam
um usuário apache e um grupo
apache, responsáveis por executar
o servidor web.
O usuário apache não precisa sequer acessar um shell, então é seguro
definir seu shell padrão como /bin/
false, por exemplo.
O usuário e o grupo, depois de
criados, devem ser informados no
arquivo de configuração do apache,
httpd.conf:
User apache
Group apache
Com esse procedimento, garantimos que o serviço HTTP seja executado com o menor privilégio possível [1].
Serviços necessários
Também é muito importante executar
no servidor somente os serviços necessários ao bom funcionamento da
aplicação web. Com isso, eliminam-se
várias fontes potenciais de insegurança,
Log robusto
O log do serviço HTTP deve ser o
mais detalhado possível, pois é por
meio dele que conseguiremos idenCAVA
VIA
GR
S CAVALO DE TR
ÓIA
PHIS
HING
VÍR
US CAVALO DE TRÓVÍR
VIAGRA
IA
LO D
E
TRÓ
SPAMs?
IA
FRAUDE
Saiba como importantes empresas estão
solucionando este problema
(11) 3522-3011
www.unodata.com.br
Linux Magazine #60 | Novembro de 2009
Baseado em software livre
Filtro de Entrada e Saída
Eficiente sem descartar mensagens importantes
Flexível e customizável
Clientes 100% satisfeitos
Acesse www.unodata.com.br e veja nossos casos
de sucesso.
PHIS
HING
ES
FRAUD
30 D
GRÁ IAS
TIS!
69
SEGURANÇA | Aplicações web
Listagem 4: Lógica de validação robusta
01 <?php
02
//autentica.php
03
session_start();
04
include (“includes/conexao.php”);
05
//Recebendo as credenciais e escapando aspas e removendo
06
//qualquer tag de script e tentativas de injeção de sql
07
$login = addslashes(strip_tags(filtroSql($_POST[“login”])));
08
$senha = $_POST[“senha”];
09
//Verificando se existe caracteres inválidos para o login
10
if (!ctype_alnum($login)){
11
die(“Caracteres Inválidos!”);
12
}
13
//Query com um hash da senha e comparada com o hash armazenado.
14
$sql = “SELECT id,
15
login
16
FROM usuarios
17
WHERE login = ‘”.$login.”’ AND
18
senha = ‘”.md5($senha).”’ “;
19
//Executando a query e suprimindo qualquer possível erro
20
$rs = @mysql_query($sql);
21
//Sucesso na execução da query
22
if($rs){
23
//Evitando que uma possível alteração de query
24
//traga mais registros que o esperado.
25
if(mysql_num_rows($rs) == 1){
26
$dados = mysql_fetch_array($rs);
27
$_SESSION[“autenticado”] = true;
28
$_SESSION[“login”] = $dados[“login”] ;
29
//Aqui pode redirecionar para a página que se deve
30
//acessar com autenticação
31
header(“Location: home.php”);
32
}
33
else{
34
die(“Login e/ou senha inválidos!”);
35
}
36
}
37
else{
38
die(“Falha na execução da query!”);
39
}
40
//Filtro para remoção de caracteres que possivelmente
41
//são usados para tentativas de sql injection
42
function filtroSql($tempString){
43
$badChars = array(“select”, “drop”, “table”, “;”, “--”, “insert”, “delete”, “update”, “xp_”,
“#”, “%”, “&”, “’”, “(“, “)”, “/”, “:”, “;”, “<”, “>”, “=”, “[“, “]”, “?”, “`”, “|”);
44
foreach ($badChars as $char) {
46
$tempString = str_replace($char, “”, $tempString);
47
}
48
return $tempString;
49
}
50
51 ?>
tificar se a aplicação está sofrendo
tentativas de ataque ou se houve
algum ataque bem sucedido [1].
Além da grande importância dos
logs HTTP, as mensagens de log dos
demais servidores da sua rede devem ser centralizadas em uma única
máquina, um servidor de log. Isso
70
facilita o gerenciamento, a análise
e a solução de problemas ocorridos
em toda a rede de uma forma geral.
Mais importante ainda é que qualquer invasão ao servidor será incapaz
de apagar seus próprios rastros, pois
estes serão enviados imediatamente
para o servidor de log [3].
Cuidado com o PHP
Em relação ao servidor de aplicação – PHP + Apache, nos exemplos
deste artigo –, também há alguns
cuidados que devemos tomar ao
configurar o PHP.
Em primeiro lugar, por questões
de segurança e desempenho, o ideal
http://www.linuxmagazine.com.br
Aplicações web | SEGURANÇA
é que o PHP seja executado como
um módulo do servidor web, e não
no modo CGI [4].
Além disso, deve-se desativar as
variáveis superglobais:
register_globals = Off
Executar o PHP no modo seguro
(safe_mode) também é uma medida
importante de segurança:
safe_mode = Off
Deve-se ainda limitar o acesso
do PHP aos arquivos com a opção
open_basedir:
open_basedir = /home/www/
Recomenda-se definir nessa diretiva o mesmo diretório usado como
document root pelo servidor web (/
home/www/, no nosso exemplo). Assim,
a aplicação só terá acesso à leitura
dos arquivos que estiverem dentro
do diretório raiz do servidor web;
isso impede, por exemplo, que a
aplicação leia o arquivo /etc/passwd
do servidor.
Sem erro
Evitar que o servidor imprima mensagens de erro para os usuários também
é uma medida importante, pois, uma
vez que o PHP imprima mensagens
de erros para um usuário, ele fornece informações importantes para um
agressor dar os primeiros passos na
preparação do ataque.
Uma maneira de perceber esse
problema antes que o pior aconteça
é usar a função error_reporting()
para ajudar a aumentar a segurança do código PHP e encontrar
o uso de variáveis potencialmente
perigosas. Ao testar seu código,
antes de colocá-lo em produção,
com E_ALL é possível encontrar rapidamente áreas onde as variáveis
podem sofrer alterações nocivas
ou outras modificações. Uma vez
Linux Magazine #60 | Novembro de 2009
que o código esteja pronto para
produção, deve-se ou desabilitar
mensagens de erro completamente
passando-se o valor 0 para a função
error_reporting(). Outra possibilidade é desligar o envio de erros
com a opção display_errors no
arquivo php.ini, evitando assim a
sondagem do código. Nesse caso,
também se recomenda definir o
caminho para o arquivo de registro
usando a diretiva error_log e ligar
a diretiva log_errors [5].
Considerações finais
Com relação à programação de
aplicações web, a solução para
cada problema demonstrado neste artigo recai sobre algum tipo de
tratamento dos dados recebidos
pela aplicação. É necessário sem-
pre fazer uma forte validação dos
dados fornecidos.
Outro ponto importante é que
não devemos atribuir certos problemas a uma determinada linguagem
de programação caso não tenham
sido levadas em consideração as
boas práticas de codificação para o
desenvolvimento de uma aplicação.
Portanto, podemos concluir que
a preocupação com a segurança da
informação deve existir desde a fase
de planejamento do sistema, assim
como em projeto de software.
Em conclusão, é importante ressaltar que o uso destas técnicas para
reforçar a segurança da aplicação
web e seu respectivo servidor não
substitui os outros mecanismos tradicionais de proteção de redes, como
firewall, IDS e IPS. n
Mais informações
[1]Mike Shema, “Hack Notes – Segurança na
Web”. Editora Campus, 2003.
[2]Comunidade OWASP-BR:
http://www.owasp.org/images/4/42/OWASP_TOP_10_2007_PT-BR.pdf
[3]Guia Foca Linux: http://focalinux.cipsga.
org.br/guia/avancado/ch-log.html
[4]Carlos Sica, Peter Villa Real, “Programação Segura
Utilizando PHP”. Editora Ciência Moderna, 2007.
[5]PHP: http://www.php.net
[6]Comunidade OWASP: http://www.owasp.org/index.php/Main_Pag
Sobre o autor
Célio de Jesus Santos é graduado em Sistemas da Informação e especialista em Segurança da
Informação. É professor na Universidade Estadual de Goiás e coordenador de desenvolvimento em
uma empresa privada.
Cloves Ferreira Junior é mestre em Ciências da Computação pela Universidade Federal de Pernambuco. É professor titular da Universidade Salgado de Oliveira e professor titular do Centro Federal de Educação Tecnológica de Goiás.
Gostou do artigo?
Queremos ouvir sua opinião. Fale conosco em
[email protected]
Este artigo no nosso site:
http://lnm.com.br/article/3115
71
Download

Aplicação web protegida