Como Ativar e Desativar Register_Globals no PHP e os Riscos


Muitos programadores PHP criam suas aplicações web e nem sabem o que é a diretiva Register Globals e nem quais os riscos que tê-la ativa pode trazer para a segurança de toda uma aplicação. Esta diretiva do PHP antigamente tinha o valor ON por padrão, mas já desde a versão 4.2.0 do PHP ela foi desativada. Contudo, devido a facilidade, devido a compatibilidade ou mesmo devido a falta de conhecimento dos mantenedores de servidores web, é fácil encontrar empresas de Hospedagem web oferecendo planos de hospedagem (compartilhados ou não) com register globals ativa. Neste artigo vou mostrar Como Ativar e Desativar Register_Globals no PHP e os Riscos. Continue lendo…

Como Ativar e Desativar Register_Globals no PHP e os Riscos

Quando register globals está ativo, o PHP trabalha de forma — ao menos para mim — um tanto ambigua. Por exemplo, todas as variáveis globais também possuem sua versão reduzida. Por exemplo, a varivável $_SERVER[‘HTTP_HOST’] também possui sua forma reduzida $HTTP_HOST. Isso é válido para todas as variáveis globais, inclusive aquelas oriundas de uma requisição web. Por exemplo, $_POST[“usuario”] também possuirá automaticamente sua versão reduzida $usuario e é aí que mora o perigo. Além do programador poder confundir-se durante a criação do script, trabalhar com register globals ativo também é suscetível de falhas e possíveis acessos indevidos. Para facilitar o entendimento, veja o script que criei para nosso teste. Comento depois:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
 
if(isset($_REQUEST["enviar"])){
    
    if($_REQUEST["usuario"] == "anderson" && $_REQUEST["senha"] == "senha123"){
        
        $autenticado = true;
    }
    
    
    if($autenticado){
 
        $url = "<a href='https://www.sugarsync.com/pf/D7948930_3742285_7622848?directDownload=true'>Clique aqui para Iniciar o Download</a>";
    
    }
 
}
 
?>
<html>
<body>
 
<p style="font-size:24px;">
<?php if(isset($url)) echo $url;?>
</p>
 
<form action="teste.php" method="post">
 
Usuario: <input type="text" name="usuario" /><br />
Senha: <input type="text" name="senha" /></br>
 
<input type="submit" value="Enviar" name="enviar" />
 
</form>
 
</body>
</html>
<?php

if(isset($_REQUEST["enviar"])){
	
	if($_REQUEST["usuario"] == "anderson" && $_REQUEST["senha"] == "senha123"){
		
		$autenticado = true;
	}
	
	
	if($autenticado){

		$url = "<a href='https://www.sugarsync.com/pf/D7948930_3742285_7622848?directDownload=true'>Clique aqui para Iniciar o Download</a>";
	
	}

}

?>
<html>
<body>

<p style="font-size:24px;">
<?php if(isset($url)) echo $url;?>
</p>

<form action="teste.php" method="post">

Usuario: <input type="text" name="usuario" /><br />
Senha: <input type="text" name="senha" /></br>

<input type="submit" value="Enviar" name="enviar" />

</form>

</body>
</html>

Este é um script com falha de segurança criado unicamente para ilustrar a suscetibilidade a falhas existente em servidores web que possuem a diretiva register globals ativa. O script possui um formulário web com um campo nome e outro senha e um botão de envio das informações. Esses dados são enviados para a própria página de teste e ao receber o formulário, o script PHP verifica se o usuário é o anderson e se a senha é a senha123, caso positivo atribui o valor true para uma variavel chamada $autenticada. Logo na sequência, o script verifica se a variavel autenticada possui o valor true e em caso positivo, atribui o url de download a outra variavel chamada de url.

A idéia aqui é liberar o download de um ebook apenas para o usuário anderson, usuário este que deverá informar a senha “senha123” para poder ter acesso ao download do livro digital. Contudo, este é um script com falhas de segurança e se estivesse hospedado em um hosting com a diretiva register globals ativa, poderia ser facilmente burlado injetando um valor para a varivavel autenticado e outro para a variavel enviar.

Por exemplo — suponde que esta página esteja com o nome teste.php — se você colocar após o final de teste.php as tais variáveis atribuindo um valor adequado, poderá ter acesso ao download mesmo sem saber a senha do usuario anderson. Veja como ficaria:

1
http://localhost/teste.php?autenticado=true&enviar=1
http://localhost/teste.php?autenticado=true&enviar=1

Note que estou testando este script em localhost, e digitando este endereço no navegador web… já sabe né?

Por incrível que pareça, mesmo sem saber o nome ou a senha do usuário, o script exibiu a url de download supostamente protegida. Mas o que aconteceu aqui? Simples, como register globals cria automaticamente uma variável reduzida para todas as variáveis globais, quando eu coloquei no url: autenticado=true e enviar=1, o PHP criou também $autenticado=true e $enviar=1. Com isso, o script entendeu erroneamente que um formulário foi enviado e que o usuário foi autenticado, liberando assim o link de download. Legal, né? rs.

Bem, claro que você poderia corrigir este script, tornando-o, de fato, seguro mesmo para register globals ativo, porém scripts inseguros como este existem a reviria aí na internet. Por este motivo, o ideal é desativar o register globals. Veja como fazer isso a seguir…

Como desativar Register Globals

Para desativar a diretiva register globals no teu servidor web, você pode dentar a seguinte dica:

a) Crie um arquivo com o nome php.ini
b) Abra este arquivo em algum editor de texto, pode ser o notepad.
c) Digite o seguinte dentro do arquivo de texto: register_globals = off
d) Salve as modificações e envie este arquivo php.ini para o diretório principal da tua hospedagem web. No caso, acesse teu domínio via FTP, navegue até a pasta principal do site — geralmente onde fica o index — e envie para lá o arquivo php.ini

Para ativar a diretiva register globals, siga os mesmos passos já descritos acima, porém em vez do valor off, coloque o valor on. Assim: register_globals = on

Emulando Register Globals

No site oficial do PHP (php.net), encontrei dois scripts interessantes para quem quer emular register globals on ou off. Veja-os abaixo:

Emular Register Globals Off

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
// Emula register_globals off
function unregister_GLOBALS()
{
    if (!ini_get('register_globals')) {
        return;
    }
 
    // Might want to change this perhaps to a nicer error
    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }
 
    // Variables that shouldn't be unset
    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');
 
    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
 
    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}
 
unregister_GLOBALS();
 
?>
<?php
// Emula register_globals off
function unregister_GLOBALS()
{
    if (!ini_get('register_globals')) {
        return;
    }

    // Might want to change this perhaps to a nicer error
    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    // Variables that shouldn't be unset
    $noUnset = array('GLOBALS',  '_GET',
                     '_POST',    '_COOKIE',
                     '_REQUEST', '_SERVER',
                     '_ENV',     '_FILES');

    $input = array_merge($_GET,    $_POST,
                         $_COOKIE, $_SERVER,
                         $_ENV,    $_FILES,
                         isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());

    foreach ($input as $k => $v) {
        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) {
            unset($GLOBALS[$k]);
        }
    }
}

unregister_GLOBALS();

?>

Emular Register Globals On

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// Emular register_globals on
if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,
        $_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, EXTR_SKIP);
    }
}
?>
<?php
// Emular register_globals on
if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,
        $_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, EXTR_SKIP);
    }
}
?>

Para que servem esses dois scripts acima? Bem, teoricamente falando, caso você tenha dois scripts, um que foi criado para trabalhar com register globals on e outro off, neste caso, um deles você deveria emular. EU surgiria a você deixar a diretiva register globals desativada por padrão e usar o script emulador de register globals on no site que foi projetado para tal.

Para você ter uma ideia, eu coloquei o código que emula o register globals off no topo do meu script de teste e a falha de segurança não mais ocorreu, mesmo estando com a diretiva register globals ativa no arquivo de configurações. Eis aí mais uma utilidade para esses emuladores de register globals on e off.

Trabalhando com Register Globals

Uma coisa que é importante deixar clara é que a diretiva register globals por sí só não é insegura, o problema é que os scripts tornam-se sucetíveis a falhas de segurança devido a imprudência dos programadores php. Por exemplo, o script de teste que criei, poderia ser corrigido da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$autenticado = false;
 
if(isset($_POST["enviar"])){
    
    if($_POST["usuario"] == "anderson" && $_POST["senha"] == "senha123"){
        
        $autenticado = true;
    }
    
    
    if($autenticado){
 
        $url = "<a href='https://www.sugarsync.com/pf/D7948930_3742285_7622848?directDownload=true'>Clique aqui para Iniciar o Download</a>";
    
    }
 
}
 
?>
<?php
$autenticado = false;

if(isset($_POST["enviar"])){
	
	if($_POST["usuario"] == "anderson" && $_POST["senha"] == "senha123"){
		
		$autenticado = true;
	}
	
	
	if($autenticado){

		$url = "<a href='https://www.sugarsync.com/pf/D7948930_3742285_7622848?directDownload=true'>Clique aqui para Iniciar o Download</a>";
	
	}

}

?>

O que foi feito aí? Bem, duas coisas. Primeiro eu defino um valor inicial false para a variável $autenticado. Com isso, mesmo que o PHP transforme $_REQUEST[“autenticado”] em $autenticado, quando ele executar a primeira linha do script o valor false será atribuído a tal variável proibindo assim que hackers tenham acessos não autorizados a conteúdos protegidos. Em segundo eu modifiquei $_REQUEST para $_POST. $_REQUEST obtém valores tanto oriundos via o método POST quanto também o GET. Por conta disso, ao verificar a variável $_POST[‘enviar’] (enviado via formulário web), o valor que foi submetido via url enviar=1 não mais será considerado.

COnclusão

Eu sempre gosto de trabalhar com register globals off, é menos ambiguo e mais seguro. Agora, caso tu pegue um script que foi criado com base em register globals on, o jeito é tomar cuidado na hora de codificar para não cometer equívocos ou deixar brechas de segurança. Ah, uma dica para quem for emular register globals off com o script sugerido: é importante colocar o código no início do script de teu site, logo após o comando session_start(), caso utilize-o.

Até o próximo artigo aqui no blog

Como Ativar e Desativar Register_Globals no PHP e os Riscos
4.8 (96.36%) 11 votes

Leave a Reply