Categorias
PHP

Segurança no PHP

Os 6 requisitos mínimos

por Er Galvão Abbott (http://www.galvao.eti.br/) na revista PHPMagazine (http://www.phpmagazine.org.br/)

logo-phpmagazine

Apresentareremos neste artigo 6 requisitos que todo o desenvolvedor PHP deveria contemplar em sua aplicação. São boas práticas e hábitos simples que implementam um nível mínimo de segurança em qualquer sistema ou ferramenta desenvolvida com a linguagem.

A linguagem PHP é, sem dúvida, uma das mais populares quando o assunto é desenvolvimento de aplicações web. Existe, porém, um preconceito muito grande com a linguagem quando a questão é segurança. Neste artigo veremos 6 requisitos básicos que toda aplicação deveria possuir e que implementarão o mínimo de segurança em tudo o que você desenvolver.

Conceito: PHP é uma linguagem mais vulnerável do que as outras?

Atualmente impera no mercado de desenvolvimento um preconceito relacionado à segurança de aplicações PHP. A linguagem é freqüentemente alvo de duras críticas por parte da própria comunidade de desenvolvimento, e não é raro presenciarmos aplicações extremamente vulneráveis que, com toda a certeza, dão razão a essas críticas.

Este preconceito, totalmente equivocado, tem suas origens na extrema flexibilidade de configuração e uso da linguagem e no número cada vez maior de desenvolvedores inexperientes que começam sua carreira desenvolvendo aplicações PHP, ignorando questões básicas, seja por falta de conhecimento ou porque estão procurando agilizar sua produção pessoal.

Este artigo não é destinado apenas aos que estão começando. É surpreendente o número de desenvolvedores mais experientes que, por terem adquirido vícios, ainda ignoram as questões que apresentaremos aqui.

Requisito #1: Esqueça register_globals!

Register_globals é, sem dúvida alguma, a diretiva de configuração mais popular e polêmica já implementada no PHP. É popular entre os desenvolvedores por tornar o processo de programação muito mais ágil e prático. É polêmica porque retira tanto do programador quanto do interpretador da linguagem a responsabilidade em definir a origem das informações utilizadas pela aplicação.

Esta diretiva causou tantos problemas que começou a vir desabilitada por default a partir da versão 4.2.0 e será eliminada na versão 6. Por isso, se você ainda programa com register_globals ligada, está mais do que na hora de mudar.

Observe o seguinte exemplo de código:

$url = "http://www.meusite.com.br/index.php";
$errMsg = "Usuário%20não%20autenticado";
if (!$autenticado) {
header("Location: $url?erro=$errMsg");
} else {
/* A aplicação age com se o usuário estivesse autenticado */
}

Este código verifica por uma variável booleana chamada $autenticado, que tipicamente viria de uma sessão aberta quando o usuário se autenticou em nossa aplicação ou mesmo de um cookie. Ao utilizarmos os recursos da register_globals, porém, não estamos dizendo ao interpretador PHP que este dado deve vir obrigatoriamente de uma destas duas fontes.

Sendo assim, o interpretador procurará por esta variável em diversas fontes (variável do servidore web, dados de formulário, cookie, arquivos enviados por upload, query string ou sessões) das quais ele obteve informações até encontrá-la, desprezando se esta fonte está correta.

Torna-se extremamente simples "enganar" a sua aplicação PHP, basta que eu chame o seu arquivo passando a variável esperada por query string.

http://www.meusite.com.br/script.php?autenticado=1

Ao receber a query string contendo a informação "autenticado", este dado será automaticamente interpretado como uma variável pelo interpretador, quer exista sessões ou cookies ou não.

Uma dúvida freqüente é "se não tenho autorização para desligar a register_globals o que eu posso fazer?". A resposta para isso é tão simples quanto tudo o mais na linguagem: programe como se ela estivesse desligada! Veja como fica o nosso código ao não utilizar a register_globals:

$url = "http://www.meusite.com.br/index.php";
$errMsg = "Usuário%20não%20autenticado";
if (!$_SESSSION['autenticado']) {
header("Location: $url?erro=$errMsg");
} else {
/* A aplicação age com se o usuário estivesse autenticado */
}

Observe a mudança: ao utilizarmos o array super global $_SESSION, estamos explicitando para o interpretador que a informação "autenticado" tem que, obrigatoriamente, vir de uma sessão. Isto significa que será impossível para o interpretador confundir este dado com um dado enviado pela query string, pois este fica armazenado em um array super global diferente:

  • $_SERVER - Informações definidas pelo servidor web (Apache, IIS etc)
  • $_GET - Informações passadas por query string ou por um formulário web utilizando o método GET
  • $_POST - Informações enviadas, tipicamente, por um formulário web utilizando o método POST
  • $_COOKIE - Informações fornecidas por um cookie HTTP
  • $_FILES - Informações fornecidas por arquivos que foram enviados via upload HTTP
  • $_ENV - Informações fornecidas pelo ambiente do servidor
  • $_REQUEST* - Informações fornecidas por GET, POST ou COOKIE

* Cuidado: O uso do array super global $_REQUEST é quase tão perigoso quanto a register_globals em si, pois nesse caso a informação pode vir de qualquer um dos 3 métodos: GET, POST ou COOKIE.

Requisito #2: Use require e não include

O comando include e seus derivados - como include_once - são freqüentemente usados em detrimento do comando require. Este fato curioso a princípio é conseqüência da similaridade do comando include com outras linguagens, como C e Java.

O que muita gente não sabe, porém, é que este comando carrega consigo um risco muito grande para sua aplicação: se por algum motivo a inclusão do arquivo falhar - erro de digitação, disco corrompido etc - será gerado um erro de nível warning, um nível leve de erro que não causa a parada da execução do script.

Utilizando o comando require, garantimos que, no caso de falha na carga do arquivo, seja gerado, além do erro de nível warning, um erro de nível fatal. Em bom português isso significa que a execução do seu script será imediatamente interrompida neste caso. Por que é bom que seu script seja interrompido no caso de falha de inclusão de outro arquivo? Simples: no caso de falhas, as variáveis, as funções, as constantes e o que mais este arquivo carregava consigo, simplesmente, não estarão disponíveis.

Requisito #3: Filtre a entrada de dados!

Um dos principais conceitos de segurança é a filtragem dos dados que são recebidos antes de utilizá-los. A falta de fitlragem é a causa de inúmeros problemas de segurança, incluindo o infame SQL Injection, ou Injeção de SQL. Observe o seguinte código:

require_once("conecta.php");
$conn = conecta();
$sql = "SELECT email FROM usuarios WHERE usuario_id = " . $_GET['uid'];
$recordSet = mysql_query($sql);
while ($record = mysql_fetch_assoc($recordSet)) {
echo $record['email'] . '<br />';
}
mysql_close();

O problema deste código é utilizar um dado informado pela query string (uid) sem fazer nenhuma filtragem, ou seja, nosso script aceitará cegamente qualquer coisa que for digitada como valor de uid. Observe a seguinte URL:

http://www.meusite.com.br/script.php?uid=198%20OR%20'x'='x'

Após a conversão dos caracteres especiais desta URL, o valor de uid será (sem aspas duplas): "198 or 'x'='x'". Note que, quando concatenarmos isto à nossa query, ela terá sofrido uma grande modificação:

SELECT email FROM usuarios WHERE usuario_id = 198 or 'x'='x'

É por isso que a chamamos de "Injeção de SQL". A parte em vermelho acima é formada de SQL válido, mas completamente alienígena à nossa plicação: ele modifica o comportamento original da query.

Observe que, com um mínimo de esforço, um usuário conseguiu expor todos os e-mails cadastrados em nossa base de dados: como foi utilizado o operador "OR" e a segunda condição ('x'='x') é sempre verdadeira, serão exibidos todos os registros.

Para evitarmos este tipo de problema, devemos aplicar um tratamento à informação antes de utilizá-la. Caso a minha query - como neste exemplo - esteja esperando um número inteiro, a solução é simples: forçamos a conversão do dado recebido para número inteiro:

require_once("conecta.php");
$conn = conecta();

settype($_GET['uid'], integer);

$sql = "SELECT email FROM usuarios WHERE usuario_id = " . $_GET['uid'];
$recordSet = mysql_query($sql);
while ($record = mysql_fetch_assoc($recordSet)) {
echo $record['email'] . '<br />';
}
mysql_close();

A partir de agora, qualquer dado enviado pela query string será primeiro convertido para inteiro e somente depois desta conversão é que o utilizaremos. No caso de uma tentativa de Injeção de SQL, nosso script considerará apenas a parte numérica (198), como deveria ser. Além disso, se por um acaso nosso script receber apenas texto, a função settype converterá isto para o número 0.

Caso a minha query esteja esperando uma string a solução reside em criar um tratamento que valide esta string. Vejamos um exemplo: possuo uma query que busca dados de um usuário através de seu endereço de e-mail:

$sql = "SELECT nome, sobrenome FROM usuarios WHERE email = '" . $_GET['email'] . "'";

Sabemos que um endereço de e-mail é formado por um nome de usuário, uma arroba e um domínio. Para fins de simplificação do exemplo, trabalharemos como se o usuário só pudesse usar letras, números e o caracterese de ponto - para quem levar a validação de e-mail a sério consulte a RFC 822. Podemos representar isso através de uma expressão regular:

code>/^[A-Z|a-z|0-9|\.|]+\@[A-Z|a-z|0-9\.|]+/

Sendo assim, só aceitaremos o dado de endereço de e-mail se ele estiver dentro dos padrões de minha expressão regular. Nosso código então ficaria assim:

require_once("conecta.php");
if (preg_match('
/code>/^[A-Z|a-z|0-9|\.|]+\@[A-Z|a-z|0-9\.|]+/', $_GET['email'])) {
$conn = conecta();

$sql = "SELECT nome, sobrenome FROM usuarios WHERE email = '" . $_GET['email'] . "'";
$recordSet = mysql_query($sql);
while ($record = mysql_fetch_assoc($recordSet)) {
echo $record['email'] . '<br />';
}
} else {
die("O dado informado não é um endereço de e-mail válido.");
}
mysql_close();
Categorias
Technology

Blogueiro gosta mesmo é de reclamar

Quanta reclamação! Basta se descontentar com alguma coisa e lá está o texto publicado. É uma quantidade considerável a de textos reclamando de alguma coisa. E... estão certos!

Aonde mais podemos reclamar do ônibus cada vez menor e com assentos que já não cabem nossas pernas (querendo nos forçar a comprar nosso carro cada vez mais rápido)? Aonde podemos reclamar que em nossa rua não há um latão de lixo sequer e o mesmo fica todo espalhado na rua? Aonde podemos reclamar do atendimento de algum posto público? Não preciso me estender mais, senão já começo a reclamar também.

Não tínhamos voz. Só podíamos reclamar no almoço em família, com a vizinha do ônibus, no trabalho. Mas nossos amigo não podem fazer muito por nós. Não tínhamos nenhuma repercussão. Agora tudo mudou. Esse espaço é nosso. Aqui quem manda somos nós e aproveitamos nossa relevância e, finalmente, podemos fazer algum barulho. Podemos aproveitar que estamos aparecendo na primeira página do Google, que estamos sendo entrevistados, que estamos aparecendo na TV.

Tem sido muito bom poder ver nossa reclamação sem idealização política, apenas nossa vivência, nosso cotidiano, o que sofremos e o que pagamos. E ninguém pode calar a nossa voz.

Isso tudo pode ser usado para o desenvolvimento de nossa sociedade, com mais qualidade de vida, com mais respeito e com mais justiça. Seremos ouvidos? Espero muito que sim. Mas estou certo que é uma manifestação (consciente ou não) que pode fazer um mundo melhor.

Categorias
Operational Systems Technology

Perigo à Vista

Li, no iMasters, que Jeff Raikes, diretor da área de negócios da Microsoft, disse: “Se quiser piratear, preferimos que seja os nossos produtos antes que qualquer outro. A longo prazo, é essencial termos uma boa base de consumidores que utilizem nossos produtos. Com o tempo, eles podem comprar o software de forma legal”, alegango que o programa de Vantagem para Windows Genuíno (Windows Genuine Advantage) tem como objetivo estimular a compra do programa original e não coibir o uso do pirata. Não é o que tenho visto.

Toda atualização, ou baixa de programa, agora é precedida pelo programa de verificação de originalidade, ou seja, quem tem o sistema não-original não atualiza mais seus sistema operacional (que a cada dia tem uma falha ou brecha descoberta) nem pode atualizar algum programa (como o Internet Explorer 7, por exemplo). Não quero defender nenhum lado, apenas observar o que considero o caminho natural daqui para a frente.

O amplo uso do computador como ferramenta de trabalho (“ele pode ser nosso maior aliado”, ouvi e concordei com um vídeo), muitos profissionais estão tendo um conhecimento a mais sobre o funcionamento dessa máquina. O Windows Vista vem apertando o cerco no que se refere ao uso do programa pirata, mesmo com as notícias de quebra que vemos atualmente, pois são todas alternativas de uso temporário. Com mais conhecimento do funcionamento de seus computadores pessoal, será natural a procura por alternativas e é aí que entram as distribuições (falo das distribuições Linux, que são as que conheço) que sofreram grande desenvolvimento nos últimos tempos.

Ela ainda exigem um certo conhecimento maior do que o habitual ligar-abrir-o-ie-entrar-no-sistema-fechar-tudo-desligar, mas já não é mais um mistério total. Hoje, com conhecimentos medianos de uso de um computador (o que cresce a cada dia) já é possível instalar uma distribuição Linux voltada para o uso de estações com grande facilidade, com a maravilhosa característica dos programas de código-aberto: não precisar pagar para utilizá-lo.

O que as distribuições Linux têm oferecido aos que resolvem embarcar nessa tentativa, até mesmo com máquinas modestas, é fascinante. Um exemplo da distribuição que tenho mais contato, o Ubuntu (pronuncia-se Ubúntu): para os acostumados com o Windows e suas janelas, ele traz janelas da mesma forma; para os ligados na facilidade das instalações de programas, há agora um método ainda mais fácil do que o atual Próximo > Próximo; para os que gostam de personalização da estação, há magníficas opções 3D; e por aí vai.

Nem todos continuarão, mas creio fortemente que muitos trilharão o caminho de sistemas operacionais alternativos, que, hoje, já não é privilégio de um conhecedor profundo de computadores, mas está à mão de usuários normais que conhecem um pouco além do básico. E normalmente não tem desapontado aos que se aventuram por um sistema lhe permite usar a inteligência. O Ubuntu já é bem familiar para os usuários de Windows e não imporá dificuldades, porém poderá se tirar muito mais se estudar um pouquinho sobre seu funcionamento, ainda mais porque é farto o material gerado pelas perguntas frequentes (e é gigantesco o prazer com que são respondidas).

É certo o desenvolvimento que será adquirido com o desafio. E a alegria com o seu crescimento.

Relacionados

Categorias
Technology

Launchy

O Launchy é um utilitário gratuito (Windows) para facilitar sua vida na hora de iniciar programas no Windows XP, sem precisar deixar sua barra de Inicialização Rápida ou o a Área de Trabalho lotados para iniciar programas, muitos dos quais usamos esporadicamente.

Depois de instalado, aperte <Alt> + <Barra de espaço> que aparecerá um prompt de comando na sua tela pra você digitar as primeiras letras do programa que quer iniciar. Enquanto se digita, o programa tenta adivinhar o programa que se quer abrir, apresentando as opções disponíveis com o que foi digitado. Encontrando o programa desejado, aperte <Enter>. Apert ESC se quiser que ele desapareça antes de abrir alguma coisa. Rápido e simples.

Dica do Henrique Costa Pereira.

Apenas saiba que quando você instalar, ele vai indexar todos os ítens que estiver no menu iniciar. Se instalou um programa depois de ter instalado o Launchy, faça-o aparecer, clique com o botão direito do mouse e selecione “Rebuild Index” que ele reindexa todo o seu menu iniciar novamente. Apenas lembre-se de sempre que atualizar o menu iniciar, reindexar o conteúdo pelo Launchy. O programinha é gratuito e disponível para download aqui!

Categorias
Banco de dados

Consultas case-insensitive e accent-insensitive no MySQL

Uma necessidade comum com dados em língua portuguesa são as buscas no bancos de dados insensível a caso e insensível a acentos.

No MySQL, até a versão 4.0, as consultas eram por padrão insensível ao caso (case-insensitive) e insensível ao acento (accent-insensitive). Isso mudou, porém, a partir da versão 4.1, que introduziu um suporte melhorado a comparações (collations) e definições de caracteres (charsets). Alguns desenvolvedores devem ter ficado surpresos com suas buscas que antes ignoravam acentos e maiúsculas e agora já exigiam que se colocasse.

A partir dessa versão, a sintaxe para uma consulta que ignora acentos e o caso seria a seguinte:

SELECT *
FROM `tab_municipios`
WHERE `NomeMunic` = _utf8 'SAO PAULO' COLLATE utf8_unicode_ci

Adaptado de Consultas case-insensitive no PostgreSQL e no MySQL