Introdução à programação
Requisições GET e POST de maneira segura usando PHP
Dentre as maneiras mais tradicionais para o envio de informações entre páginas de internet, os formulários eletrônicos são amplamente utilizados, pois facilitam, e muito, a transferência de dados.
Neste artigo, serão abordados dois métodos de requisições, quais sejam, GET e POST, para o envio e recebimento de dados a partir de um formulário HTML, usando PHP. Também, serão apresentados os problemas mais comuns envolvendo segurança da informação, como Cross-Site Scripting (XSS) e SQL Injection, e como resolvê-los com sanitização adequada.
Vamos começar pela teoria: o que são requisições GET e POST, e como estas se diferenciam? — se você preferir, pode pular para a próxima seção, onde partiremos para a prática.
Entendendo os métodos GET e POST
Inicialmente, o Hypertext Transfer Protocol (HTTP), que você está acostumado a ler nos endereços das páginas web — assim como o seu “irmão”, o HTTPS, que é uma versão com criptografia e, portanto, mais segura (daí o “S” ao final, do inglês “Secure”) –, foi desenvolvido como um protocolo para servir à transmissão de documentos, e atua como intermediário entre os navegadores de internet e os servidores web.
Em outras palavras, o HTTP é um protocolo que serve como uma “ponte”: ele coleta uma requisição do navegador de internet (também chamado de browser); então, a leva até o servidor; espera por uma resposta; e, finalmente, retorna com esta nova informação para o browser.
Em geral, essas requisições guardam consigo alguns metadados no seu “cabeçalho” (do inglês, “header”), que contém mensagens utilizadas para realizar determinado comportamento no cliente ou no servidor. Além disso, as requisições HTTP podem assumir diferentes modelos.
Os modelos de requisição HTTP mais utilizados são o GET e o POST, mas também há outras requisições em sua especificação técnica, como o PUT
, HEAD
, DELETE
, PATCH
e OPTIONS
. Para os fins deste artigo, vamos focar apenas nos dois mais comuns.
O método GET
O método GET é usado quando se quer obter dados de uma determinada origem ou recurso específico. Portanto, só devem ser usados para recuperar dados, e sua query string
é enviada e exibida no endereço URL, por exemplo: https://www.youtube.com/watch?v=fJ9rUzIMcZQ&t=3m5s
.
Neste exemplo, quando inserimos a URL no browser, estamos solicitando ao servidor do YouTube, neste caso, um recurso específico: que recupere os dados do vídeo v
identificado como fJ9rUzIMcZQ
. Assim que o servidor “devolver” a requisição, o protocolo HTTP informará ao browser como exibir o vídeo, neste nosso exemplo, o vídeo oficial da música “Bohemian Rhapsody”, da banda britância Queen.
Observe que em nosso exemplo, o segundo parâmetro da requisição GET, o parâmetro t
, informa o tempo de início que esperamos em nossa resposta, neste caso, a partir dos 3min e 5s. E, ainda, os parâmetros v
e t
são separados pelo caractere &
, que indica ao protocolo HTTP onde começam e onde terminam os pares "chave-valor" desses parâmetros. Assim, o servidor sabe exatamente que você busca o vídeo v=fJ9rUzIMcZQ
, a partir do tempo t=3m5s
.
Em geral, as requisições GET têm limitação de comprimento — para a maioria dos browsers, este limite é de 8 KB, ou 8192 bytes, na URI — e, porque servem apenas para requisitar dados, não têm capacidade de modificá-los. Além disso, podem ser armazenadas em cache, no histórico e nos favoritos do navegador. Por esta razão, é muito importante que nunca sejam usadas para transmitir dados sensíveis, como CPFs e senhas de usuários.
💡 Alguns desenvolvedores, no entanto, ignoram esta regra e expõem dados pessoais e sensíveis de pessoas na internet. No Brasil, em razão da Lei Geral de Proteção de Dados (LGPD), esta prática pode gerar enormes transtornos, como penalidades graves à empresa ou àquele que opera e gerencia esses dados, caso haja o vazamento de dados pessoais. O ideal, portanto, é jamais transmitir dados pessoais sensíveis via método GET.
O método POST
Por sua vez, o método POST é utilizado para enviar dados para o servidor, para atualizar ou criar um novo recurso.
Diferentemente do método GET, o método POST não expõe as informações no endereço URL. Neste caso, os dados são transmitidos no corpo da requisição HTTP, como segue:
POST /atualizar/formulario.php HTTP/1.1
Host: youtube.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 45
usuario=Stevie&playlist=British&v=fJ9rUzIMcZQ
Neste exemplo, estamos informando ao servidor Host: youtube.com
que faremos uma requisição de método POST
ao endereço /atualizar/formulario.php
, utilizando as especificações técnicas do protocolo HTTP/1.1
. Além disso, indicamos que há uma informação de 45 caracteres (Content-Length: 45
), no formato de conteúdo Content-Type
padrão, cujo valor é application/x-www-form-urlencoded
. Por fim, a nossa informação se encontra na última linha, e contém 3 parâmetros: usuario
, playlist
, e v
.
Apesar de mais seguras, as informações que trafegam no corpo da requisição HTTP podem ser interceptadas por maus agentes. A melhor prática, portanto, é realizar estas transmissões usando criptografia, via protocolo HTTPS, que dificulta a leitura dessas informações.
Vamos supor que o servidor do YouTube reconheceu nossa requisição, e que este endereço é válido. Sendo assim, em nosso exemplo, o vídeo informado, o qual recebemos previamente, será adicionado à playlist British
do usuário identificado como Stevie
.
Note que esta é uma requisição una, que provavelmente não será repetida. Por isso, em regra, o método POST, diferentemente do GET, não é armazenado em cache nem no histórico do navegador do cliente, e nem pode ser salvo nos seus favoritos. Quanto ao limite de caracteres, as requisições POST não têm restrições no tamanho das mensagens, o que permite o envio de artigos completos, como este do Medium, através de um formulário eletrônico HTML, por exemplo. Além disso, o método POST tem suporte a uma grande variedade de Content-Type
s, inclusive de documentos binários, strings e números.
💡 Por essas razões, o método POST é geralmente preferível em relação ao GET. Porém, há situações em que é interessante incluir os dados da requisição no endereço URL, por exemplo, em formulários de busca ou na exibição de páginas, documentos e vídeos, porque queremos que o cliente possa repetir o procedimento facilmente, podendo (re)acessar o endereço através do histórico do navegador.
Criando formulários eletrônicos com HTML e PHP
Agora que compreendemos como funcionam os métodos GET e POST na teoria, vamos à pratica, criar um formulário HTML, e fazê-lo enviar e receber informações usando o PHP.
💡 Há diversas maneiras de fazê-lo, inclusive via JavaScript e AJAX, que não precisa que o usuário recarregue a página no browser, transmitindo as informações assincronamente. Para os fins deste artigo, vamos focar apenas nas tecnologias HTML e PHP.
Inserindo o form na página
O primeiro passo para criar um formulário é informar a estrutura do elemento <form>
que irá conter os campos para inserção dos dados, como este:
<!-- origem.html -->
<form method="GET" id="formulario" name="formulario" action="destino.php">
</form>
No fragmento acima, estamos utilizando o método GET, definido em method="GET"
, para enviar as informações que estarão inseridas no formulário, cujo nome foi definido em name="formulario"
, à página de destino que se encontra em action="destino.php"
.
Inserindo os campos no form
O próximo passo é inserir os campos, ou input
s ao nosso formulário, em que iremos preencher os valores. Vamos atualizar nosso arquivo de origem, desta forma:
<!-- origem.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Formulário eletrônico</title>
</head>
<body>
<form method="GET" id="formulario" name="formulario" action="destino.php">
<label for="idusuario">Identificador do usuário:</label>
<input type="text" id="idusuario" name="idusuario"> <br /> <label for="idplaylist">Identificador da playlist:</label>
<input type="text" id="idplaylist" name="idplaylist"> <br /> <label for="v">Identificador do vídeo:</label>
<input type="text" id="v" name="v" value="fJ9rUzIMcZQ"> <br /> <button type="submit">Enviar dados</button>
</form>
</body>
</html>
No exemplo acima, inserimos 3 campos, definidos com a tag HTML <input>
, e 1 botão que envia os dados do formulário, criado com o elemento HTML <button type="submit">
.
Também, acrescentamos rótulos aos campos de texto, usando as marcações <label>
. Note que o valor dos atributos for
de cada elemento label
corresponde ao atributo id
de um campo input
. Assim, o rótulo <label for="idplaylist">
se refere especificamente ao campo que contém o atributo id="idplaylist"
correspondente, e vice-versa.
💡 É possível inserir valores pré-definidos aos campos, acrescentando o valor corresponde ao atributo
value
em cada elemento HTML<input>
.
Por sua vez, o atributo name
presente em cada campo <input>
será utilizado para obter os
valores informados no campo correspondente quando partirmos para o PHP.
O resultado final, exibido no browser do cliente, deve ser semelhante a este:
Lendo os dados com PHP
Finalizado nosso formulário HTML, podemos partir à próxima etapa, em que definimos os elementos da página destino usando PHP.
O código-fonte abaixo, inserido no arquivo destino.php
, será executado pelo PHP assim que o usuário enviar os dados do formulário que criamos anteriormente.
<!-- destino.php -->
<?php
// Imprime os valores de cada campo na página
echo(
"O usuário identificado como " . $_GET["idusuario"] . " adicionou o vídeo de ID " . $_GET["v"] . " à playlist " . $_GET["idplaylist"] . "."
);
?>
Note que utilizamos da variável superglobal $_GET[]
para obter os valores informados pelo usuário, que foram transmitidos pelo protocolo HTTP. Assim, para cada campo <input>
que criamos no formulário previamente, seu atributo name
correspondente deverá ser informado dentro da variável superglobal. Por exemplo: o campo <input>
que contiver o atributo name="idusuario"
poderá ser obtido no PHP usando $_GET["idusuario"]
.
O PHP possui algumas variáveis nativas superglobais definidas por padrão, como $_GET
, $_POST
, e $_REQUEST
. Lembre-se que o uso de cada uma delas é correspondente ao método de requisição HTTP que foi empregado para transmissão dos dados, ou seja, deve estar de acordo com o que definimos no atributo method
do nosso elemento <form>
.
💡A variável superglobal
$_REQUEST
, do PHP, é capaz de conter as informações de ambos os métodos$_GET
e$_POST
, além de eventuais cookies transmitidos em$_COOKIE
. Contudo, seu uso não é recomendado para todos os casos: o ideal é que o desenvolvedor conheça os métodos de entrada e de saída das informações que trafegam em seu servidor, de modo a evitar comandos mais genéricos.
Então, separamos as strings e as variáveis no PHP com o caractere .
, de modo que cada fragmento de texto esteja contido entre os caracteres "
, no começo e ao término da sentença. Finalmente, imprimimos na tela do usuário toda a expressão entre os parênteses com a função echo()
.
📝 Aprender fazendo
Você notou que o endereço URL da página destino.php
contém os valores inseridos no formulário da página de origem?
Exercício #1: Reescreva o código-fonte do formulário que desenvolvemos para que estes valores sejam transmitidos usando outro método de requisição, de modo que as informações estejam à salvo da leitura por bisbilhoteiros ou pessoas desautorizadas. Depois que finalizar, você pode conferir a resposta final.
Aumentando a segurança do formulário HTML
Nosso formulário está pronto, finalmente! Contudo, podemos aumentar a segurança da nossa página, protegendo a leitura das informações pelo PHP.
Esta é a nossa última etapa. Vamos adicionar uma camada extra de segurança, ainda que básica, para impedir o PHP de executar comandos no momento em que recebe e exibe os valores informados pelo cliente.
💡 A regra na programação é nunca confiar cegamente nos valores informados pelo usuário. Infelizmente, um grande número de maus agentes têm explorado problemas técnicos em páginas de internet para coletar informações sigilosas, ou danificar os servidores executando comandos inesperados. Por isto, é muito importante que você proteja, de antemão, as requisições transmitidas e o servidor, afinal, se os interesses do usuário forem legítimos, ele também será beneficiado pelo aumento de segurança da sua aplicação.
A técnica que formata e transforma os valores informados pelo usuário em strings mais simples é chamada de sanitização (do inglês, “sanitization”). Por padrão, o PHP contém uma coleção de funções nativas que auxiliam nesta etapa, como as seguintes:
htmlspecialchars()
- Converte caracteres especiais, como&“”<>
, para entidades HTML;htmlentities()
- Função similar à anterior, porém converte um maior número de caracteres para entidades HTML;strip_tags()
- Remove as tags HTML e PHP de uma string, como hiperlinks e comentários.
Portanto, quando utilizamos a sanitização adequada, assim que o servidor receber uma informação indevida — por exemplo, <script>alert(‘Alerta intrusivo’);</script>
-, ela será transformada e estará “sanitizada” para a exibição, e não deverá exibir uma mensagem de aviso na tela do cliente neste caso.
💡 Note que, neste exemplo, utilizamos de um script, em tese, inofensivo — no máximo, incômodo para o usuário. Porém, é importante reiterar: você deve proteger e sanitizar as informações, sempre. Em outros casos, um mau agente poderia transmitir scripts maliciosos — esta técnica é conhecida como Cross-Site Scripting, ou XSS — ou executar comandos lesivos à base de dados — geralmente chamadas de SQL Injection, ou “injeção de SQL”, em tradução livre do inglês.
Vamos, portanto, editar o código-fonte da nossa página em PHP, acrescentando uma dessas funções de sanitização. Nosso arquivo final deverá ficar assim:
<!-- destino.php -->
<?php
// Imprime os valores de cada campo na página
echo(
"O usuário identificado como " . htmlspecialchars($_GET["idusuario"], ENT_QUOTES, "UTF-8") . " adicionou o vídeo de ID " . htmlspecialchars($_GET["v"], ENT_QUOTES, "UTF-8") . " à playlist " . htmlspecialchars($_GET["idplaylist"], ENT_QUOTES, "UTF-8") . "."
);
?>
O resultado final, exibido no navegador de internet, deve ser semelhante à figura abaixo:
📝 Aprender fazendo
Você já observou que a maioria dos sites e indexadores de busca na internet utilizam o parâmetro q
para transmitir os dados informados pelo usuário nas requisições de consulta ao servidor?
Exercício #2: Crie um formulário de busca, usando HTML e PHP, que contenha, no mínimo, 1 campo de texto e 1 botão para enviar os dados, de modo que o endereço URL na página de destino exiba o parâmetro q
(do inglês, “query”, que quer dizer “consulta”), o qual deverá receber os valores, sanitizados, inseridos no campo de texto pelo cliente. Depois que finalizar, você pode conferir a resposta final.
Conclusão
Enfim, terminamos! Finalizamos nosso formulário eletrônico, criado em HTML, que é capaz de transmitir dados via métodos de requisição HTTP, neste caso, GET ou POST — sobre os quais compreendemos, também, como funcionam -, e enviá-los à página de destino, escrita em PHP. A página de destino, então, recebe, trata e exibe as informações na tela do usuário. E, ainda, sanitizamos os valores informados pelo usuário com fins de evitar problemas graves de segurança da informação.
Próximos passos 🚶
Segurança na internet nunca é demais, e sempre há algo mais para aprender e aplicar. Para construir aplicações mais seguras, não deixe de acompanhar os próximos artigo desta série, e leia o tópico sobre Segurança no Manual do PHP.
Se restou alguma dúvida, ou se tens alguma sugestão de como construir aplicações mais seguras usando PHP, compartilha nos comentários. 📣
Referências
[1] “HTTP Request Methods”, em w3schools: https://www.w3schools.com/tags/ref_httpmethods.asp.
[2] “HTTP”, em MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/pt-BR/docs/Web/HTTP.
[3] “GET”, em MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Methods/GET.
[4] “POST”, em MDN Web Docs (Mozilla Developer Network): https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Methods/POST.
[5] “htmlspecialchars”, em Manual do PHP: https://www.php.net/htmlspecialchars.
[6] “htmlentities”, em Manual do PHP: https://www.php.net/htmlentities.
[7] “strip_tags”, em Manual do PHP: https://www.php.net/strip_tags.
[8] “Superglobais”, em Manual do PHP: https://www.php.net/manual/pt_BR/language.variables.superglobals.php.