PHP e Null Bytes issues

if (file_exists(realpath($_GET['teste'] . ".php"))){
echo 'OK';
}
else{
echo 'Fail';
}

Aparentemente esta verificação é bastante segura né?

Infelizmente não. O PHP usa o padrão de strings usado em C (aquelas terminadas com ‘\0′), o que gera um problema bastante conhecido chamado de Null Byte issue [1].

O que acontece se seu $_GET['teste'], aparentemente seguro, tiver um ‘\0′?
Sua função realpath vai verificar apenas o $_GET['teste'] e nem vai saber que existe um “.php”

Faça o teste:

http://localhost/labs/teste.php?teste=/etc/passwd%00

(%00 é o código hexadecimal aceito pelos browsers para o \0)

E o resultado:

OK

[1] http://en.wikipedia.org/wiki/Null_character

Você ainda usa a “tabela admin”? Você pode estar correndo riscos…

Creio que seja “procedimento padrão” dos programadores PHP, ao desenvolver sistemas de login, criar uma tabela admin com um campo username e outro campo password, e quando o usuário realiza o login, o sistema executa uma query mais ou menos do tipo: $sql = 'SELECT * FROM admin WHERE user=' . $user . ' AND password = "' . $password . '";

Claro, pode haver variações de segurança como “escapestring” e md5 na senha. Mas a idéia é basicamente esta. Vejamos agora porque eu acho este tipo de procedimento inseguro.

1 – Todos os “usuários” do sistema executam com o mesmo usuário no banco de dados. Como o sistema deve ter um “super-usuário” que poderá fazer tudo no sgdb, todos os usuários do sistema poderão fazer tudo. O que quero dizer é que, em qualquer brecha mínima no sistema, um usuário comum (mas mal intencionado) poderá fazer drop em uma tabela inteira.

2 – A senha do usuário do banco de dados deverá ficar em um arquivo .php legível. Há um tempo atrás, eu utilizava um servidorzinho destes de 9,90 por mês para hospedar meu site. Um dia tive a curiosidade de saber o que tinha no /tmp do servidor. Então fiz uma página que recebia uma string, que se esta fosse um arquivo executava um system(“cat $valor”), e se esta fosse um diretório, executava um system(“ls -ls $valor”). O que eu percebi: Todos os usuários do servidor executavam na web com o mesmo usuário (normalmente o www). Logo o www deverá ter permissão para ler todos os arquivos. Então tive a curiosidade de listar o /home. E depois o /etc/.alias do apache. Indo desta forma, consegui observar o arquivo de configuração de banco de dados de um dos usuários. E depois disto, entrar no php MyAdmin.
Com isto, vocês já imaginam o tamanho potencial da catástrofe né?
Deixei este servidor e migrei para a dreamhost pois após enviar um e-mail alertando os administradores do servidor sobre falha, fui respondido com algo como: “Estamos cientes, mas você tem alguma dica de como resolver?”.

Tá tá, realmente a falha 1 pode ser resolvida se você for um programador extremamente observador e não deixar passar absolutamente nada. Sinceramente, acho isto quase impossível. E também se você gostar de re-inventar a roda, re-desenvolvendo todo um sistema de segurança em cima da aplicação, quando poderia ser usado o que “já vem pronto” do banco de dados.

Solução: Por a lógica de segurança em cima do banco de dados. Porquê? Porque ela já está implementada e tende a ser mais segura.

Explicação:

A idéia toda é, ao invés de fazer o “login” usando seleção você atrela o usuário ao banco de dados. Ao invés de “criar um usuário” na tabela admin, você cria um usuário no banco de dados e loga-se com ele. Entendeu?

No PHP ficaria algo assim:

mysql_connect($usuario,$senha,$database);

Após isto, em banco de dados de verdade (digo PostGress, Oracle e afins), basta você gerenciar as permissões (select, insert, drop´s, etc…) dos usuário em tabelas específicas. Por exemplo: Não faz sentido um usuário comum ter acesso à tabela de configuração, ou o mesmo poder dar drop em uma tabela qualquer.

Também utilizar Stored Procedures e Views ajudam bastante. Exige um pouco de conhecimento de DBA, mas deixa sua aplicação mais robusta, além de ser um procedimento muito mais seguro.

Sei que aplicações comerciais de grande porte trabalham desta forma. Mas a grande maioria dos programadores (principalmente web) nunca viram ou trabalharam com este tipo de abordagem. A intenção deste post é apenas dar uma idéia de uma forma diferente, e mais segura, de trabalhar.

Espero que este post incite uma discussão sobre esta e outras abordagem. E você, leitor, como trabalha?

Comentem!

[]’s e Feliz Páscoa.

O que fazer durante a atualização do seu DNS?

Olá pessoas,

Hoje venho escrever sobre uma idéia que tive para solucionar um certo problema.

A algum tempo atrás necessitei trocar um site de um servidor para o outro, mas como este site servia algumas aplicações críticas (é, talvez nem tão críticas), o mesmo não poderia sair em nenhum momento do ar. Ou seja, deveria estar rodando perfeitamente tanto em um host quanto em outro.

Mas, como testar um sistema em um novo servidor? Substituindo as informações de DNS. Mas, no melhor dos casos demora uma hora. E se der errado? Substitui de volta? São pelo menos 3 horas de um sistema off-line. Acho que não é uma solução interessante para aplicações críticas né?

Solução inteligente.

Adicionar nova entrada no /etc/hosts. Simples assim.
Desta forma, você poderá testar sua aplicação no seu novo servidor, e todos os seus clientes continuarão acessando no antigo! Assim, quando você tiver certeza de que tudo está funcionando, você substitui oficialmente o DNS no seu registro de domínios. Legal né?

Passo a Passo

1) Primeiro pegue as informações de DNS de seu novo host.
Um exemplo seria o dreamhost: ns1.dreamhost.com

2) Com o comando ping, descubra qual o IP do servidor DNS

$ ping ns1.dreamhost.com
PING ns1.dreamhost.com (66.33.206.206) 56(84) bytes of data.
64 bytes from ns1.dreamhost.com (66.33.206.206): icmp_seq=1 ttl=44 time=233 ms

--- ns1.dreamhost.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

rtt min/avg/max/mdev = 233.172/233.172/233.172/0.000 ms

O Ip do servidor aqui é: 66.33.206.206

3) Abra o arquivo /etc/hosts (como root é claro), e adicione a linha

66.33.206.206 seu_site.com.br www.seu_site.com.br

4) Agora, no seu browser acesse o seu_site.com.br, e perceba que você estará acessando no novo servidor, e não mais no oficial.
Agora você pode testar a sua aplicação online, corretamente, sem colocar em risco a continuidade do seu serviço oficial. =)

Qualquer dúvida estamos ae!

Acho que esta solução não funciona para quem usa servidores proxy’s

[]’s
Danilo Cesar

Injection… Estou realmente seguro?

Olá,

Bom, neste segundo artigo aqui venho falar um pouco sobre segurança em sistemas PHP.

Creio que muitos acham que este é um assunto batido: Também acho!
Mas, depois de verificar alguns sistemas em PHP começei a perceber alguns “istupros” à segurança na internet…

(more…)