Usando Register Globals

Talvez a mudança mais controversa no PHP é quando o valor padrão para a diretiva do PHP register_globals passou de ON para OFF no PHP 4.2.0. Confiança nesta está diretiva foi bastante pública e muitas pessoas nem mesmo sabiam que ela existia e assumiam que ela é apenas a forma como o PHP trabalha. Esta página irá explicar como alguém pode escrever um código inseguro com esta diretiva, mas mantenha em mente que a diretiva por si só não é insegura, mas o seu uso incorreto sim.

Quando on, register_globals injetará (veneno) em seus scripts todos os tipos de variáveis, como variáveis request de formulários HTML. Isto junta-se com o fato deo PHP não exigir inicialização de variáveis siginifica que escrever códigos inseguros é muito mais fácil. Não foi uma decisão difícil, mas a comunidade PHP decidiu, por definição, desabilitar esta diretiva. Quando on, as pessoas usavam variáveis ainda sem saber realmente, com certeza, de onde elas vinham e podiam apenas supor. Variáveis internas que estão definidas no próprio script conseguem se misturar com dados requisitados enviados pelos usuários e desabilitando register_globals muda isto. Vamos demonstrar com um exemplo de mal uso de register_globals:

Exemplo 16-14. Exemplo de uso incorreto com register_globals = on

<?php
// definir $authorized = true apenas se o usuário está autenticado
if (authenticated_user()) {
    
$authorized = true;
}

// Por isso nós primeiro não inicializamos $authorized como false, isto poderia
// ser definido através de register_globals, como por GET auth.php?authorized=1
// então, qualquer um pode ser visto como autenticado!
if ($authorized) {
    include
"/highly/sensitive/data.php";
}
?>

Quando register_globals = on, nossa lógica acima pode ser comprometida. Quando off, $authorized não pode ser setada via request portanto isto é mais agradável, apesar disso é realmente uma boa prática de programação inicializar as variáveis primeiro. Por exemplo, em nosso exemplo acima nós poderíamos ter feito primeiro $authorized = false. Fazendo isto primeiro significa que nosso código acima trabalharia com register_globals on ou off enquanto usuários, por definição, estariam desautorizados.

Um outro exemplo é aquele das sessões. Quando register_globals = on, nós poderíamos também usar $username em nosso exemplo abaixo, mas novamente você deve imaginar que $username poderia, também, vir de outros meios, tal como GET (pela URL).

Exemplo 16-15. Exemplo de uso de sessões com register_globals on ou off

<?php
// Nós saberíamos de onde $username veio, mas fazer com $_SESSION é
// para dados de sessão
if (isset($_SESSION['username'])) {
    
    echo
"Olá <b>{$_SESSION['username']}</b>";

} else {
    
    echo
"Olá <b>Guest</b><br />";
    echo
"Você gostaria de logar?";

}
?>

É até possível tomar medidas preventivas para quando a formação de variável está sob tentativa. Se você já sabe de antemão de onde a variável está vindo, você pode ver se os dados submetidos está vindo de um tipo de submissão impróprio. Enquanto não está garantido que dados não foram formados, ele exige a um atacante que advinhe o tipo correto de formação da variável. Se você toma cuidado de onde os dados requisitados vêm, você pode usar $_REQUEST já que ele contém um misto de dados GET, POST e COOKIE. Veja também a seção do manual sobre usando variáveis externas do PHP.

Exemplo 16-16. Detectando simples envenamento de variável

<?php
if (isset($_COOKIE['MAGIC_COOKIE'])) {
    
    
// MAGIC_COOKIE vem de um cookie.
    // Certifique se de validar os dados de cookies!

} elseif (isset($_GET['MAGIC_COOKIE']) || isset($_POST['MAGIC_COOKIE'])) {
   
   
mail("admin@example.com", "Possível tentativa de transgressão", $_SERVER['REMOTE_ADDR']);
   echo
"Violação da segurança, admin foi alertado.";
   exit;

} else {
   
   
// MAGIC_COOKIE não é setado por este REQUEST

}
?>

É claro que, simplesmente desligando register_globals não significa que seu código está seguro. Para cada peça de dados que é submetido, ele também seria verificado de outras formas. Sempre faça a validação de dados de seus usuários e inicialize as suas variáveis! Para verificar por variáveis não inicializadas você pode ligar error_reporting() para mostrar níveis de erros E_NOTICE.

Disponibilidade das superglobais:: Desde o PHP 4.1.0, os arrays superglobais como $_GET , $_POST, $_SERVER, etc. sempre estão carregados. Para mais informações, leia a seção do manual sobre superglobals