Segurança do Sistema de Arquivos
Table of Contents
O PHP está sujeito à segurança encontrada na maioria dos sistemas de servidor com respeito à permissões de arquivos e diretórios. Isso permite que seja controlado que arquivos no sistema podem ser lidos e por quem. É preciso ter cuidado com quaisquer arquivos que são lidos por todos para assegurar que eles podem ser lidos por todos os usuários que têm acesso ao sistema de arquivos.
Já que o PHP foi projetado para permitir acesso em nível de usuário ao sistema de arquivos, é possível escrever um script PHP que permitirá ler arquivos do sistema como o /etc/passwd, modificar suas conexões de rede, enviar inúmeros trabalhos de impressão, etc. Isso tem algumas implicações óbvias, já que é necessário garantir que os arquivos lidos e gravados são apropriados.
Considere o seguinte script, onde um usuário indica que quer apagar um arquivo no seu diretório "home". Isso presume uma situação onde uma interface web PHP é usada regularmente para controle de arquivos, então o usuário do Apache tem permissão de apagar arquivos nos diretórios "home" dos usuários.
Example #1 Verificação fraca de variáveis resulta em....
<?php
// Remove um arquivo do diretório "home" do usuário
$username = $_POST['user_submitted_name'];
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
unlink("$homedir/$userfile");
echo "O arquivo foi removido!";
?>
"../etc/"
e "passwd"
.
O código então leria efetivamente:
Example #2 ... um ataque ao sistema de arquivos
<?php
// Remove um arquivo de qualquer lugar no disco rígido
// que o usuário do PHP tenha acesso. Se o PHP tiver acesso de administrador (root):
$username = $_POST['user_submitted_name']; // "../etc"
$userfile = $_POST['user_submitted_filename']; // "passwd"
$homedir = "/home/$username"; // "/home/../etc"
unlink("$homedir/$userfile"); // "/home/../etc/passwd"
echo "O arquivo foi removido!";
?>
- Dar permissões limitadas ao usuário web binário do PHP.
- Checar todas as variáveis que são enviadas.
Example #3 Checagem com mais segura do nome do arquivo
<?php
// Remove um arquivo do disco rígido que o
// usuário do PHP tenha acesso.
$username = $_SERVER['REMOTE_USER']; // usando um mecanismo de autenticação
$userfile = basename($_POST['user_submitted_filename']);
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (file_exists($filepath) && unlink($filepath)) {
$logstring = "Removido $filepath\n";
} else {
$logstring = "Falhar ao remover $filepath\n";
}
$fp = fopen("/home/logging/filedelete.log", "a");
fwrite($fp, $logstring);
fclose($fp);
echo htmlentities($logstring, ENT_QUOTES);
?>
"../etc/"
, o sistema está novamente exposto. Por
essa razão, é preferível escrever uma verificação mais personalizada:
Example #4 Verificação mais segura do nome do arquivo
<?php
$username = $_SERVER['REMOTE_USER']; // usando um mecanismo de autenticação
$userfile = $_POST['user_submitted_filename'];
$homedir = "/home/$username";
$filepath = "$homedir/$userfile";
if (!ctype_alnum($username) || !preg_match('/^(?:[a-z0-9_-]|\.(?!\.))+$/iD', $userfile)) {
die("Usuário/arquivo inválido");
}
// etc.
?>
Dependendo do sistema operacional, existe uma variedade enorme de arquivos
com os quais se preocupar, incluindo dispositivos (/dev/
ou COM1), arquivos de configuração (arquivos /etc/
e arquivos .ini
), áreas de armazenamento de arquivo bem conhecidas (/home/,
My Documents), etc. Por essa
razão, normalmente é mais fácil criar uma política onde se proibe
tudo exceto aquilo que for explicitamente permitido.