O perigo no gerenciador de uploads do PHP
O PHP é capaz de receber o upload de qualquer browser que siga a norma RFC-1867, o que permite o upload de arquivos cliente => servidor. Ele ainda provê o controle total de quem pode fazer o upload e o que fazer com o arquivo após sua transferência, mas mesmo com esse controle, somente poucas pessoas sabem do perigo real do mal uso desse recurso.
Parte 3: is_uploaded_file() e move_uploaded_file()
Vejamos também as funções is_uploaded_file() e
move_uploaded_file() para entender sobre as falhas que
poderiam surgir durante a nossa programação.
is_uploaded_file ( string filename) -- Diz se o arquivo foi uploaded
Retorna TRUE se o arquivo com o nome filename foi uploaded via HTTP POST. Isto é útil para ter certeza que um usuário malicioso não está tentando confundir o script em trabalhar em arquivos que não deve estar trabalhando --- por exemplo, /etc/passwd.
Este tipo de confirmação é importante principalmente se existe alguma chance que qualquer coisa feita com os arquivos carregados poderiam revelar o seu conteúdo para o usuário ou mesmo para outros usuários no mesmo sistema.
is_uploaded_file() está disponível somente em versões do PHP 3 depois da 3.0.16 e em versões do PHP 4 posteriores a 4.0.2. Se você ainda está utilizando uma versão anterior, você pode utilizar o seguinte código para se proteger:
Nota: O exemplo seguinte não funcionará em versões do PHP posteriores a 4.0.2. Isto depende de uma funcionalidade interna do PHP que mudou depois dessa versão.
is_uploaded_file ( string filename) -- Diz se o arquivo foi uploaded
Retorna TRUE se o arquivo com o nome filename foi uploaded via HTTP POST. Isto é útil para ter certeza que um usuário malicioso não está tentando confundir o script em trabalhar em arquivos que não deve estar trabalhando --- por exemplo, /etc/passwd.
Este tipo de confirmação é importante principalmente se existe alguma chance que qualquer coisa feita com os arquivos carregados poderiam revelar o seu conteúdo para o usuário ou mesmo para outros usuários no mesmo sistema.
is_uploaded_file() está disponível somente em versões do PHP 3 depois da 3.0.16 e em versões do PHP 4 posteriores a 4.0.2. Se você ainda está utilizando uma versão anterior, você pode utilizar o seguinte código para se proteger:
Nota: O exemplo seguinte não funcionará em versões do PHP posteriores a 4.0.2. Isto depende de uma funcionalidade interna do PHP que mudou depois dessa versão.
<?php
/* Teste de arquivo carregado pelo usuário */
function is_uploaded_file($filename) {
if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
$tmp_file = dirname(tempnam('', ''));
}
$tmp_file .= '/' . basename($filename);
/* Pode haver uma barra no final do php.ini... */
return (ereg_replace('/+', '/', $tmp_file) == $filename);
}
/* Utilize isto se por acaso você não tiver
* move_uploaded_file() em versões antigas: */
if (is_uploaded_file($HTTP_POST_FILES['userfile'])) {
copy($HTTP_POST_FILES['userfile'], "/place/to/put/uploaded/file");
} else {
echo "Possível ataque de carregamento de arquivo:
filename '$HTTP_POST_FILES[userfile]'.";
}
?>
/* Teste de arquivo carregado pelo usuário */
function is_uploaded_file($filename) {
if (!$tmp_file = get_cfg_var('upload_tmp_dir')) {
$tmp_file = dirname(tempnam('', ''));
}
$tmp_file .= '/' . basename($filename);
/* Pode haver uma barra no final do php.ini... */
return (ereg_replace('/+', '/', $tmp_file) == $filename);
}
/* Utilize isto se por acaso você não tiver
* move_uploaded_file() em versões antigas: */
if (is_uploaded_file($HTTP_POST_FILES['userfile'])) {
copy($HTTP_POST_FILES['userfile'], "/place/to/put/uploaded/file");
} else {
echo "Possível ataque de carregamento de arquivo:
filename '$HTTP_POST_FILES[userfile]'.";
}
?>
Bem... Moral da história:
Pense naqueles sites que possuem sistemas do tipo "fale conosco" com suporte a anexos e confirmação que não utilizam esse tipo de validação? E como seria se um usuário "fuçador" começasse a explorar um fórum com o sistema de upload mal implementado? Não precisamos nem pensar muito no que um usuário malicioso pode fazer. Um exemplo seria o usuário setar o campo de upload com o caminho /etc/passwd, ou ./index.php. Enfim, qualquer arquivo do servidor e recebê-lo pela confirmação em seu e-mail.
Mas a função move_uploaded_files() que eu utilizei no exemplo possui uma peculiaridade. Vale lembrar que quando ela 'move' o arquivo no servidor, a mesma manda os arquivos somente com permissões de escrita (o que no caso de imagens para um site por exemplo não é viável), podendo sempre, lógico, alterar estas permissões.
Como deu pra ver, as possibilidades para falhas são inúmeras e quem não fizer esse tipo de validação está sujeito a muita dor de cabeça no futuro ^^
Fonte: Manual do PHP
[]`s
Ragen
Perdi meu tempo pois tudo o que li aqui, já tinha lido no manual do PHP e nada me acrescentou.
Paulino Michelazzo