Modificando diretamente superglobais

20

Eu já vi pessoas (que geralmente escrevem um bom código) alterar diretamente a $_POSTmatriz com um código como este:

// Add some value that wasn't actually posted
$_POST['last_activity'] = time();

// Alter an existing post value
$_POST['name'] = trim($_POST['name']);

// Our pretend function
// Pass the entire $_POST array as data to work with in the function
// The function update_record() will read only the values we actually need
update_record($_POST);

// ...That sure was easier than creating a new array 
//  with only the $_POST values we actually need.

Faz sentido que update_record()não deva acessar diretamente $ _POST, para que possamos passar outras matrizes de dados para ele, por exemplo, mas certamente isso é preguiçoso, com design ruim ou possivelmente errado? No entanto, ainda estamos passando um array válido para update_record(), então por que criar um novo?

Este não é o ponto da questão, apenas um exemplo de uso. No entanto, ouvi muitas pessoas dizerem que isso não deve ser feito com $_REQUESTdados, e é uma prática ruim. Mas por que? Parece bastante inofensivo.

Exemplos:

  • Definir um valor padrão $_GET(ou postar) que realmente não existe

  • Adicionando $_POSTvalores que não foram realmente lançados após o envio de um formulário

  • Limpar diretamente ou filtrar os $_GETvalores ou chaves da matriz muito cedo no script (saneamento de fallback ... por que não?)

  • Configurando um $_POSTvalor manualmente antes do envio do formulário para preencher uma entrada com um valor padrão (quando a entrada lê $_POSTseu valor padrão; eu fiz isso)

  • Criando seus próprios $_SERVERvalores? Claro, ei, por que não?

  • E os outros, como $_COOKIEe $_SESSION? Claro que temos que modificar diretamente, certo? Então por que não os outros?

A modificação direta de superglobais nunca deve ser feita ou é aceitável em alguns casos?

Wesley Murch
fonte
Eu concordo com os itens 1, 2 e 3, porque é um uso inesperado (especialmente os itens 1 e 2).
Kevin Peno
Boa pergunta. A modificação de matrizes globais está errada da mesma maneira que o uso de valores globais está errado. Além disso, essas matrizes têm seu objetivo (passar parâmetros de fora) que torna a alteração delas uma maneira direta de mexer no código. Porém, acredito que algumas dessas matrizes podem ser higienizadas no início do script, apenas para não causar problemas no código.
Tadeck
1
Estou usando wrappers de matriz de entrada OO (filtragem implícita), que imprimem um aviso adicional quando as variáveis ​​$ _GET ou $ _POST são adulteradas. Ainda é possível, mas deve ser restrito a situações estreitas. (Sinalização de Cross-módulo, embora apenas o despachante / controlador de frente deve precisar dele.)
mario
@mario: Eu adoraria ouvir mais sobre como você conseguiu isso, se você pode dar uma olhada para esta questão: stackoverflow.com/questions/12954656
Wesley Murch

Respostas:

16

Dado que o PHP já está definindo esses superglobais, não acho que seja ruim modificá-los. Em alguns casos, pode ser a melhor maneira de resolver problemas ... principalmente ao lidar com códigos de terceiros que você não pode modificar facilmente. (Eles podem usar $_GETdiretamente ou assumir que alguma chave existe $_SERVERetc.)

No entanto, de um modo geral, acho que é uma prática ruim quando você está escrevendo seu próprio código. A modificação dos $_REQUESTdados com algum filtro dos bastidores executado automaticamente em todas as páginas provavelmente apresentará efeitos colaterais. (Veja todos os problemas que as "aspas mágicas" causaram como prova.)

Portanto, se você não fizer isso (filtrar automaticamente os superglobais), o seguinte não trará benefícios:

$_POST['foo'] = filter($_POST['foo']);

quando você pode facilmente fazer:

$foo = filter($_POST['foo']);

Eu acho que é muito mais claro fazer a distinção em todo o site que $_POSTe sempre$_GET são dados não filtrados e não confiáveis, e eles nunca devem ser usados ​​como estão.

Ao copiar o valor filtrado para outra variável, você está afirmando que "entendo o que estou fazendo ... filtramos essa entrada e é seguro usá-la".

konforce
fonte
Obrigado pela contribuição, minha internet está fora há quase 2 dias, por isso não tive a chance de responder a ninguém. No exemplo, modifiquei $ _POST e usei-o como uma matriz de dados para passar para uma função de atualização, presumindo que existam várias outras chaves $ _POST que leremos nessa função. Eu preferiria criar uma nova matriz, mas já vi pessoas fazendo isso, por isso ainda estou um pouco inseguro quanto a chamá-lo de "código incorreto", mas acho que é pelo menos assim. Eu acho que sempre que você sentir necessidade de fazer isso, sempre haverá uma maneira melhor.
Wesley Murch #
1
@Wesley, a principal razão pela qual é "ruim" é que torna muito mais provável que você esqueça de higienizar alguns dados do usuário. No seu exemplo, você modifica uma chave e passa toda a matriz. E se alguns desses dados contiverem entrada maliciosa que não é processada? É muito melhor criar essa nova matriz manualmente, copiando apenas as coisas de que você precisa $_POST, higienizando à medida que avança. E com relação a outras pessoas que fazem isso ... bem, muitas pessoas escrevem código PHP muito ruim, mas isso não é desculpa para você também. :)
konforce 14/05
Eu acho que deveria ter enfatizado as outras aplicações de abuso de superglobais, além de apenas limpar os dados. Eu provavelmente deveria ter deixado de fora completamente e redigido uma pergunta mais clara, as pessoas gostam particularmente de entender os aspectos de segurança e geralmente ignoram o resto. Para não parecer ingrato, eu realmente aprecio o feedback. Vou esperar um dia e dar a esta marca de verificação, pois você abordou alguns pontos positivos, mas perdeu a parte da votação durante os 3 minutos em que a pergunta era nova :) Obrigado novamente!
Wesley Murch #
9

Em geral, sugiro que você não modifique as super globais predefinidas para que fique claro o que são dados higienizados e os dados brutos / não confiáveis.

Outros podem sugerir que, se você limpar os superglobais no início do ciclo de solicitação, não precisará se preocupar com eles em nenhum outro lugar.

Eu sempre os combinava quando você precisava deles com:

$id = (int)$_POST['id'];

ou similar.

Em termos de outras variáveis, é boa prática para não escrever a qualquer um $_GET, $_POST, $_REQUEST, $_SERVERou $_COOKIE. $_SESSIONno entanto, é diferente porque geralmente você deseja gravar dados na sessão que persistem em diferentes solicitações da sessão.


fonte
2
Mais razões pelas quais esses tipos de globais devem desaparecer substituídos por objetos / métodos que podem ser chamados para obtê-los quando necessário. Por que setcookieexiste, mas recebemos cookies via $_COOKIE? Além disso, como $_COOKIEsó é definido quando a sessão atual é iniciada e nunca é atualizada, é necessário que você altere / defina cookies nas duas áreas para que as áreas posteriores do código tenham informações atualizadas.
Kevin Peno
Obrigado James, eu estou offline há um tempo, então não pude responder. Para resumir uma longa história, concordo com você. Sempre existe uma solução melhor do que escrever para postar / obter / etc, mas ainda não tenho certeza se é considerada uma idéia estritamente ruim, como em " nunca faça isso nunca ". Então, se eu me deparar com esse tipo de código novamente, você acha que tenho o direito de "chamá-los" com códigos desleixados ou isso pode ser usado de maneira inteligente e segura às vezes?
Wesley Murch
@ Wesley Se fosse "nunca faça isso nunca", os superglobais provavelmente seriam estritamente somente leitura - eles não são. Eu chamaria de prática recomendada configurá-los ou substituí-los no código do aplicativo - pelos motivos mencionados.
Michel Feldheim
3

Você deveria evitá-lo. Talvez algum tempo você tenha esquecido de higienizar alguma coisa, para recuperar dados perigosos. Se você copiar os dados em uma nova estrutura enquanto estiver limpando

  • Você só tem, o que você quer / precisa e não o que está em $_POSTdemais
  • Você provavelmente receberá um erro, se a matriz recém-criada estiver faltando algumas chaves ou estiver ausente.

Outros scripts adicionais podem assumir que a matriz está intocada e pode reagir curiosa.

KingCrunch
fonte
2

Nunca gostei da ideia de modificar superglobal porque é enganosa. É uma maneira hacky rápida de fazer algo que provavelmente haverá uma maneira melhor de fazer.

Se você alterar o valor de $_POST, por exemplo, estará dizendo que o software recebeu dados que não recebeu.

O REAL PROBLEMA

Existe uma situação da vida real em que isso se torna um grande problema:

Imagine que você está trabalhando em equipe. Em um mundo ideal, todos usam a mesma sintaxe, mas não vivemos em um mundo ideal. Um desenvolvedor, John, gosta de acessar os dados publicados usando $_POST. Ele muda algo nos post vars:

$_POST['ranking'] = 2; // John has changed ranking from 1 to 2 for whatever reason

Então você tem outro desenvolvedor, Chris, que prefere usar filter_inputpara acessar dados inseridos (por exemplo, GET, POST, SERVIDOR, BOLINHO), pois ele protege o software ao processar dados que o usuário pode adulterar. Em sua parte do software, ele precisa obter o valor postado de ranking. Sua parte do código é DEPOIS de John.

$ranking = filter_input(INPUT_POST, 'ranking', FILTER_SANITIZE_NUMBER_INT);
// $ranking = 1

No exemplo acima, alterando uma superglobal, você quebrou o PHP. John definiu o valor de $_POST['ranking']2 por qualquer motivo, mas agora Chris recebeu um valor de 1

Quando não vejo outra maneira de fazer isso:

Trabalhei em um projeto que usava o wordpress como seu blog por trás de um balanceador de carga da AWS. Isso altera o valor de $_SERVER['remote_address']. Nesse caso, o outro desenvolvedor não teve escolha a não ser fazer o seguinte:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $parts[0];
}

Conclusão

Há quase certamente uma maneira melhor do que mudar superglobais

Luke Madhanga
fonte
1

Eu acho que a verdadeira pergunta aqui é "por que você deve modificar o tema?". Não vejo nenhum motivo válido para fazê-lo. Se você precisar limpar uma imput, poderá usar uma variável local…

A menos que o código seja curto o suficiente (digamos, com menos de 50 linhas), modificar essas superglobais apenas tornaria seu código mais difícil de manter e entender.

A propósito, você não precisa passar $ _POST para a função, pois é uma matriz superglobal que pode ser acessada mesmo dentro do escopo local de uma função.


fonte
3
Mas ele deveria passar.
Caso contrário
Bem, isso depende do que o método dele faz. Se ele foi projetado apenas para analisar o que estiver no array $ _POST, ele não precisa transmiti-lo. Obviamente, se isso serve a um propósito mais geral / abstrato, você tem razão.
2
@ Thomas, eu concordo com o rei aqui. Mesmo que sejam globais, você não deve usar nada global em outros escopos, pois causa um acoplamento rígido (razão pela qual a função não pode ser reutilizada). Como exemplo, se a função é higienizar dados, por que apenas higieniza $_POSTdados? A transferência $_POSTfaz com que a função desinfete todos os dados.
Kevin Peno
0

Depois de responder inicialmente a essa pergunta dizendo que não deveria haver motivo para modificar superglobais, estou editando essa resposta com um exemplo de uma época em que decidi.

Atualmente, estou trabalhando em uma tabela de reescrita de URL na qual a requestcoluna direciona o usuário para a targetcoluna correspondente .

Por exemplo, um requestpode ser blog/title-heree targetpode ser blog.php?id=1.

Como blog.phpestá esperando $_GETvariáveis, e eu não quero mudar header("Location:"), estou fazendo algo assim:

$uri    = explode('?', $uri_request)[0];
$params = explode('?', $uri_request)[1];
parse_str($params, $_GET);

Isso cria uma $_GETmatriz que contém os parâmetros pretendidos passados ​​pela targetcoluna.

Por fim, eu recomendaria fortemente não modificar superglobais, a menos que você precise .

rybo111
fonte