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 inclui Netscape Navigator 3 ou posterior, Microsoft Internet Explorer 3 com um patch da Microsoft ou posterior sem patch).
Isto permite que se faça o upload de arquivos de texto e binários. Com as funções de autenticação e manipulação de arquivos do PHP, você tem o controle completo de quem pode fazer o upload de arquivo e o que fazer com o arquivo após seu upload e sabe-se que o PHP também suporta o método PUT para upload de arquivos como o usado por Netscape Composer e W3C's Amaya clients.
Uma tela para upload de arquivo pode ser criada com um formulário especial parecido com este:
A _URL_ deve indicar um arquivo PHP. O campo hidden MAX_FILE_SIZE deve vir antes do campo input e seu valor é o limite aceito de tamanho do arquivo. O valor é em bytes.
Atente-se que o valor de MAX_FILE_SIZE é um aviso PARA O BROWSER. É fácil contornar este limite. Então não conte que o browser irá obedecer a sua vontade, porém o que foi estabelecido para maximum-size no PHP1, ou seja, server-side, não pode ser enganado.
1. Definido no arquivo php.ini
As variáveis definidas para o upload de arquivos são diferentes, dependendo da versão e da configuração. A autoglobal $_FILES existe desde o PHP 4.1.0. A array $HTTP_POST_FILES existe desde o PHP 4.0.0. Estas arrays irão conter toda a informação de upload do arquivo.
Usar $_FILES é preferido. Se a opção register_globals é setada "on"(ativa) no php.ini, os nomes de variáveis relacionados também existirão. O padrão de register_globals é "off"(desativa) desde o PHP 4.2.0, ou seja, apartir da versão 4.2.0 tornou-se padrão o uso de variáveis do tipo $_POST['var'], $_GET['var'], $_COOKIE['var'], $_SESSION['var'], $_FILES['var'], invés do simples uso de $var ou $HTTP_POST_FILES, por exemplo.
Mas recapitulando... Os conteúdos de $_FILES do nosso script de exemplo é como segue. Note que isso assume que o nome do upload do arquivo é userfile, como o usado no exemplo acima.
$_FILES['userfile']['name']
O nome original do arquivo no computador do usuário.
$_FILES['userfile']['type']
O tipo mime do arquivo, se o browser deu esta informação. Um exemplo pode ser "image/gif".
$_FILES['userfile']['size']
O tamanho, em bytes, do arquivo.
$_FILES['userfile']['tmp_name']
O nome temporário do arquivo, como foi guardado no servidor.
$_FILES['userfile']['error']
O código de erro associado a este upload de arquivo. ['error'] foi adicionado no PHP 4.2.0.
Nota: Em versões anteriores a 4.1.0 o nome era $HTTP_POST_FILES e não é uma variável autoglobal como $_FILES é. PHP 3 não suporta $HTTP_POST_FILES.
Quando register_globals esta em "on"(ativo) no php.ini, variáveis adicionais estão disponíveis. Por exemplo, $userfile_name será igual a $_FILES['userfile']['name'], $userfile_type será igual a $_FILES['userfile']['type'], etc. Lembre-se que desde o PHP 4.2.0, o padrão para register_globals é "off"(desativo). É preferível não depender desta opção.
Isto permite que se faça o upload de arquivos de texto e binários. Com as funções de autenticação e manipulação de arquivos do PHP, você tem o controle completo de quem pode fazer o upload de arquivo e o que fazer com o arquivo após seu upload e sabe-se que o PHP também suporta o método PUT para upload de arquivos como o usado por Netscape Composer e W3C's Amaya clients.
Uma tela para upload de arquivo pode ser criada com um formulário especial parecido com este:
<form enctype="multipart/form-data" action="_URL_" method="post"> <input type="hidden" name="MAX_FILE_SIZE" value="30000"> Send this file: <input name="userfile" type="file"> <input type="submit" value="Enviar Arquivo"> </form>
A _URL_ deve indicar um arquivo PHP. O campo hidden MAX_FILE_SIZE deve vir antes do campo input e seu valor é o limite aceito de tamanho do arquivo. O valor é em bytes.
Atente-se que o valor de MAX_FILE_SIZE é um aviso PARA O BROWSER. É fácil contornar este limite. Então não conte que o browser irá obedecer a sua vontade, porém o que foi estabelecido para maximum-size no PHP1, ou seja, server-side, não pode ser enganado.
1. Definido no arquivo php.ini
As variáveis definidas para o upload de arquivos são diferentes, dependendo da versão e da configuração. A autoglobal $_FILES existe desde o PHP 4.1.0. A array $HTTP_POST_FILES existe desde o PHP 4.0.0. Estas arrays irão conter toda a informação de upload do arquivo.
Usar $_FILES é preferido. Se a opção register_globals é setada "on"(ativa) no php.ini, os nomes de variáveis relacionados também existirão. O padrão de register_globals é "off"(desativa) desde o PHP 4.2.0, ou seja, apartir da versão 4.2.0 tornou-se padrão o uso de variáveis do tipo $_POST['var'], $_GET['var'], $_COOKIE['var'], $_SESSION['var'], $_FILES['var'], invés do simples uso de $var ou $HTTP_POST_FILES, por exemplo.
Mas recapitulando... Os conteúdos de $_FILES do nosso script de exemplo é como segue. Note que isso assume que o nome do upload do arquivo é userfile, como o usado no exemplo acima.
$_FILES['userfile']['name']
O nome original do arquivo no computador do usuário.
$_FILES['userfile']['type']
O tipo mime do arquivo, se o browser deu esta informação. Um exemplo pode ser "image/gif".
$_FILES['userfile']['size']
O tamanho, em bytes, do arquivo.
$_FILES['userfile']['tmp_name']
O nome temporário do arquivo, como foi guardado no servidor.
$_FILES['userfile']['error']
O código de erro associado a este upload de arquivo. ['error'] foi adicionado no PHP 4.2.0.
Nota: Em versões anteriores a 4.1.0 o nome era $HTTP_POST_FILES e não é uma variável autoglobal como $_FILES é. PHP 3 não suporta $HTTP_POST_FILES.
Quando register_globals esta em "on"(ativo) no php.ini, variáveis adicionais estão disponíveis. Por exemplo, $userfile_name será igual a $_FILES['userfile']['name'], $userfile_type será igual a $_FILES['userfile']['type'], etc. Lembre-se que desde o PHP 4.2.0, o padrão para register_globals é "off"(desativo). É preferível não depender desta opção.
mesmo depois de ter lido a algum tempo, voltei aqui pra deixar meu comentário e tirar umas dúvidas... Parabéns...
12/12/2003 2:11pm
(~21 anos atrás)
Existe, pelo menos no meu server, uma limitação quanto ao tamanho do arquivo, não passa nada acima de 1MB, e eu não tenho nenhum proxy que possa causar esse tipo de limitação. O apache da minha máquina é o 2.alguma coisa. Grato !!!! Fabiano.
10/12/2003 10:42am
(~21 anos atrás)
Seria mesmo mais prudente bloquear os arquivos com extensão não permitida do client-side. Alguém sabe como fazer isso? Só que depois tem que bloquear também no php .. um usuário mal intensionado vai saber mesmo burlar a restrição client-side.
Marlon
Marlon
07/12/2003 10:45am
(~21 anos atrás)
acho que o legal não é bloquear os tipos de arquivos, e sim somente permitir, vc escolhe oque pode fazer upload e permite esses, o resto, bloqueia tudo, na certa que é melhor, pois vc pode esquecer alguma coisa e ai ja vio.
26/11/2003 11:44am
(~21 anos atrás)
Concordo Ragen,
a documentação é linda :)
por isso existe gente traduzindo ela
para o nosso também lindo idioma :P
a documentação é linda :)
por isso existe gente traduzindo ela
para o nosso também lindo idioma :P
12/11/2003 5:45am
(~21 anos atrás)
Valeu Marco,
Mas se você der uma pesquisada no manual do PHP você vai ver que tudo isso que eu disse está na documentação disponivel no php.net.
A documentação do PHP é linda :)
[]`s
Ragen
Mas se você der uma pesquisada no manual do PHP você vai ver que tudo isso que eu disse está na documentação disponivel no php.net.
A documentação do PHP é linda :)
[]`s
Ragen
11/11/2003 6:41pm
(~21 anos atrás)
O seu artigo, além de breve, foi capaz de resumir de forma bastante interessante o processo de upload. Recentemente estive desenvolvendo alguns scripts para upload e suas dicas são pertinentes. Todo cuidado é pouco. Parabéns!
11/11/2003 6:37pm
(~21 anos atrás)
é realmente quem ja teve problemas com upload sabe o que pode acontecer :)
muito bom artigo!!
e os comentários são novamente muito preciosos!
muito bom artigo!!
e os comentários são novamente muito preciosos!
06/11/2003 8:01am
(~21 anos atrás)
Muito bem lembrado.
Geralmente esse tipo de validação por extensão se torna realmente mais fácil mesmo.
Mas mostrei as outras formas no caso de alguém precisar fazer um sistema de upload de um arquivos que compartilhe uma extensão comum ao servidor.
[]`s
Ragen
Geralmente esse tipo de validação por extensão se torna realmente mais fácil mesmo.
Mas mostrei as outras formas no caso de alguém precisar fazer um sistema de upload de um arquivos que compartilhe uma extensão comum ao servidor.
[]`s
Ragen
06/11/2003 4:24am
(~21 anos atrás)
Bacana Ragen, bastante didático.
Uma dica legal também (se você puder fazer isso) é limitar os arquivos pela extensão,
tipo: se o nome do arquivo não terminar em '.htm' ou .html' ou '.txt', paramos o processo.
Só isso evita boa parte das possibilidades de ataques, pois os arquivos administrativos do linux, como o /etc/shadow ou passwd podem ser do tipo text/plain, mas não tem extensão.
$fname = $_FILES['userfile']['name'];
if(!preg_match("/\.htm$/",$fname) and
!preg_match("/\.html$/",$fname) and
!preg_match("/\.txt$/",$fname)) die("Tipo de arquivo não permitido");
Uma dica legal também (se você puder fazer isso) é limitar os arquivos pela extensão,
tipo: se o nome do arquivo não terminar em '.htm' ou .html' ou '.txt', paramos o processo.
Só isso evita boa parte das possibilidades de ataques, pois os arquivos administrativos do linux, como o /etc/shadow ou passwd podem ser do tipo text/plain, mas não tem extensão.
$fname = $_FILES['userfile']['name'];
if(!preg_match("/\.htm$/",$fname) and
!preg_match("/\.html$/",$fname) and
!preg_match("/\.txt$/",$fname)) die("Tipo de arquivo não permitido");
05/11/2003 7:42pm
(~21 anos atrás)