O PHP está sujeito à segurança implementada na maioria dos sistemas de servidor com respeito às permissões de arquivos e diretórios. Isto permite controlar que arquivos no sistema podem ser lidos. É preciso ter cuidado com arquivos que são acessíveis globalmente para garantir que sejam seguros para leitura 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, é totalmente possível escrever um script PHP que permitirá ler arquivos de sistema como o /etc/passwd, modificar conexões de rede, enviar tarefas massivas de impressão, etc. Isto tem algumas implicações óbvias, já que é necessário garantir que os arquivos lidos e gravados são os 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 gerenciamento de arquivos, de forma que o usuário Apache tem permissão para apagar arquivos nos diretórios "home" dos usuários.
Exemplo #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:
Exemplo #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:
$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.
Verificar todas as variáveis que são enviadas.
Exemplo #3 Verificação 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 = "Falha 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
este motivo, é preferível escrever uma verificação mais personalizada:
Exemplo #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 devemos nos preocupar, incluindo entradas de dispositivos (/dev/
ou COM1), arquivos de configuração (/etc/
e .ini), áreas de armazenamento de arquivo bem conhecidas (/home/,
Meus Documentos), etc. Por este
motivo, normalmente é mais fácil criar uma política onde se proíbe
tudo exceto aquilo que for explicitamente permitido.