Cuidado com o cabeçalho Host do HTTP
A especificação da versão 1.1 do protocolo HTTP descreve um cabeçalho chamado Host, este cabeçalho contém o nome de host do site que o usuário deseja acessar. O cabeçalho serve para que o servidor web possa identificar qual recurso o usuário está requisitando quando o servidor atende múltiplos nomes de host (sites).
Apesar de exigir a presença do cabeçalho, a RFC do protocolo, no item 5.2, autoriza que o mesmo seja ignorado caso o cliente HTTP faça a requisição utilizando uma URI absoluta. Abaixo você pode ver um exemplo de requisição com URI relativa e outro com URI absoluta, respectivamente:
GET /index.php HTTP/1.1
Host: exemplo.com.br
GET http://exemplo.com.br/index.php HTTP/1.1
Host: exemplo.com.br
Ignorar o valor Host não representa um problema de segurança, exceto quando o programador assume que ele sempre representa o servidor atual. Infelizmente isso acontece bastante, muitos colocam códigos como o abaixo para diferenciar entre modo de produção e modo de desenvolvimento em seus programas:
Para explorar a falha de segurança, é necessário que você crie uma requisição
HTTP customizada que envia o host correto pela URI mas enviar localhost
no
cabeçalho Host
. Podemos fazer isso usando telnet:
[higor@whiterice tmp]$ telnet exemplo.com.br 80
Trying 127.0.0.1...
Connected to exemplo.com.br
Escape character is '^]'.
GET http://exemplo.com.br/index.php HTTP/1.1
Host: localhost
HTTP/1.1 200 OK
Date: Sun, 27 Oct 2013 16:11:42 GMT
Server: Apache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
MODO DE DESENVOLVIMENTO. A SENHA DE admin É "123tr0c4r!"
Connection closed by foreign host.
E assim nós descobrimos a senha de admin
.
Se você quer evitar este tipo de problema, você deve utilizar o nome do
servidor ($_SERVER['SERVER_NAME'])
em vez do valor de Host
($_SERVER['HTTP_HOST']
). Porém ainda existe algo fazer se você utiliza o
Apache para servir suas páginas, será necessário dizer ao Apache que você quer
que a variavel de ambiente SERVER_NAME
seja igual ao nome que você deu ao seu
servidor (ServerName
), pra isso você deve ativar a opção UseCanonicalName
:
Se você utiliza PHP e/ou Apache, você pode ler mais sobre a solução e sobre o problema neste resposta do StackOverflow.