Skip to content

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.

6 Comments

  1. Não vejo problema em usar um super-usuário do banco de dados para todos. Ao invés da maneira que você fez (suscetível a SQL Injection) basta fazer algo como

    $user = mysql_real_escape_string($user);
    $pass = mysql_real_escape_string($pass);

    E mandar bala na query:

    $query = “SELECT * FROM admin WHERE user='{$user}’ AND pass='{$pass}'”;

    Ah, péssima idéia verificar o usuário com o mysql_connect, já que estabelecer a conexão com o banco de dados é o procedimento mais caro (tempo, recursos, etc).

    Eu postei a algum tempo atrás uma função que quebra um galho em termos de processamento de queries. http://simplesideias.com.br/php-e-sql-injection/

    Quanto ao item 2: isso é questão de configuração do servidor.
    Servidores mal-configurados irão listar tudo o que você quiser. Servidores bem configurados — Dreamhost, por exemplo — só listam arquivos de sua home.

    Posted on 08-Apr-07 at 4:05 pm | Permalink
  2. Almoços de sexta-feira rendendos posts então!? hehehe…

    Bacana o post! Mas só um comentário… Quantos servidores você conhece quem permitem um cliente criar N usuários para uma mesma base dados? :)

    Posted on 08-Apr-07 at 5:13 pm | Permalink
  3. Bom post e ótimo comentário, eu também conheço poucos servidores hoje em dia que permitam tais configurações, acho que por isso que os programadores Web (como eu) não conhecem essa abordagem, pois é pouco usada, mas no momento que você se utiliza de aplicações comerciais com certeza essa prática melhora o desempenho …
    só fica uma pergunta … e se eu precisasse guardar mais informações do usuário ?

    Guardaria numa tabela a parte ? … isso eu já não acho legal …

    De qualquer jeito ótimo post!

    Grande Abs

    Posted on 09-Apr-07 at 8:57 am | Permalink
  4. Danilo Cesar

    Respondendo aos comentários..
    —-
    Nando: Discordo de você cara. Não estamos falando apenas de querys de logins. Estamos falando de um sistema todo.
    Quanto à ser ruim verificar o usuário com mysql_connect, você tem que fazer isto de qualquer forma. Você é obrigado a fazer isto.
    —-
    Furlan:
    Almoços realmente são produtivos pra jogar conversa fora e pensar em novos posts. Um servidor por exemplo que faz isto é o DreamHost. Mas infelizmente ele não tras um banco de dados de verdade, apenas o MySQL.
    —-
    Rangel, sim, neste caso você precisa de um lugar para guardar suas informações de usuário. E sim, ficaria em uma tabela. Mas veja que você não precisa fazer select na tabela sempre, apenas para puxar informações do banco quando necessário for.

    Apenas me complementando. Como citei o MySQL no Post, esqueçam. O MySQL não tem as funcionalidades necessárias para este tipo de abordagem.

    Posted on 09-Apr-07 at 1:27 pm | Permalink
  5. Você tem razão. Geralmente, ignora-se a camada de segurança que o próprio gerenciador do banco de dados possui, ao fazer com que todas as requisições de uma aplicação web sejam efetuadas sob a mesma credencial.

    Porém, essa má prática é adotada porque poucos serviços de hospedagem oferecem flexibilidade para o gerenciamento dos bancos de dados, como criação de usuários adicionais, bancos de dados separados (schemas), etc…

    Posted on 10-Apr-07 at 12:54 pm | Permalink
  6. Respondendo a resposta :)

    >> Um servidor por exemplo que faz isto é o DreamHost. Mas infelizmente ele não tras um banco de dados de verdade, apenas o MySQL.

    MySQL? Eu disse “bando” ou “banco” de dados? hehehe…
    Mas ainda assim, ele oferece para você um usuário com permissão para criar outros usuários!?

    Veja bem, eu não sou contra a idéia toda em si! Assim como nós discutimos aquele dia, eu concordo que o sistema fica mais seguro (ainda mais se integrar a autenticação do banco de dados com a autenticação do Apache), só que eu acho que utilizar essa “técnica” hoje em dia, ainda é inviável! :)

    Posted on 16-Apr-07 at 2:12 am | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*