Segurança Total em um Banco de Dados PostgreSQL

Disponibilidade para o primeiro ataque

A segurança de banco de dados é a maior preocupação com os aplicativos baseados na Web de hoje. Sem controle, você arrisca expor informações sensíveis sobre sua empresa ou, pior ainda, sobre seus valiosos clientes. Neste artigo, aprenda sobre medidas de segurança que você pode tomar para proteger seu banco de dados PostgreSQL.

Robert Bernier, PostgreSQL Business Intelligence Analyst, Medio Systems

Robert Bernier é analista de PostgreSQL Business Intelligence na Medio Systems, que é líder na tecnologia emergente de pesquisa de mídia. Ele foi um consultor de PostgreSQL para muitos líderes em suas respectivas indústrias, incluindo telefones celulares, Wall Street, centros de pesquisa científica, contratados da defesa dos EUA, e departamentos de TI das universidades e faculdades Ivy League. Ele é um defensor do PostgreSQL e escreveu para Sys-Admin, Hakin9, PHP Solutions, e muitos sites on-line incluindo Linux.com, PHPbuilder.com, PHP Magazine, Linux Weekly News e o portal da Web O'Reilly. Ele contribuiu nos livros BSD Hacks e Multimedia Hacks. Ele também mantém o pg-live, http://pg-live.info, que é usado no mundo todo em conferências, trade shows e sessões de treinamento para fazer o perfil dos incríveis recursos do PostgreSQL.



16/Dez/2009

Introdução

Existem muitas histórias na imprensa sobre crackers acessando bancos de dados corporativos. Foram-se os dias quando adolescentes eram os autores da maioria dos ataques a dados. Hoje, a colheita de dados é um grande negócio e é realizado por especialistas dedicados que trabalham dentro de uma infraestrutura corporativa. Não é uma questão de como você pode evitar a tentativa de acesso não-autorizada — você não pode — mas, em vez disso, como você pode reduzir o efeito quando ele ocorrer.

Definições

Hacker— Um hacker explora, investiga e descobre por meio do entendimento da tecnologia em um nível raramente duplicado em circunstâncias normais. Ser chamado de hacker por seus colegas é uma medalha de honra não porque você faz alguma coisa ruim, mas porque seu conhecimento não tem paralelo.

Cracker— Um hacker com má intenção, como vandalismo, fraude em cartão de crédito, roubo de identidade, pirataria ou outros tipos de atividade ilegal.

Este artigo explora os desafios de proteger seu servidor de banco de dados PostgreSQL (também conhecido como Postgres). O PostgreSQL é um poderoso sistema de banco de dados relacional de objeto de software livre. Ele tem uma arquitetura comprovada com reputação para confiabilidade, integridade de dados e correção. Ele executa em todos os principais sistemas operacionais, incluindo Linux®, UNIX®, e Windows®. Ele é completamente compatível com o ACID, e tem suporte completo para chaves estrangeiras, junções, visualizações, acionadores e procedimentos armazenados (em vários idiomas).

Certifique-se de fazer o download das listas de código de amostra usadas neste artigo.


O administrador ideal

Na grande tradição do UNIX, o PostgreSQL foi projetado desde a base para complementar o S.O. no qual se sustenta. Otimizar o PostgreSQL para seu potencial máximo requer conhecimento além da demanda tipicamente esperada do administrador de banco de dados médio (DBA - average database administrator).

Resumidamente, o DBA de PostgreSQL ideal tem o seguinte conhecimento:

  • Conhecedor da teoria relacional e familiarizado com o SQL 92, 99 e 2003, respectivamente.
  • Conhece como ler código de origem, preferencialmente C, e pode compilar código de origem no Linux.
  • Pode administrar sistema e se sente confortável com o system-V UNIX ou Linux.
  • Pode manter, se necessário, os vários itens de hardware tipicamente encontrados em uma loja de TI. Entende a camada TCP OS, pode criar uma subrede em uma rede, ajustar firewalls, etc.

Muitos DBAs possuem somente as habilidades para administrar, monitorar e ajustar o próprio banco de dados. Porém, o PostgreSQL é integrado para também contar com os utilitários do S.O. É raro um DBA que domine todas essas disciplinas, mas ter esse conhecimento possibilita ao DBA do PostgreSQL realizar mais em menos tempo do que seria possível de outra forma.


Revisão dos privilégios de acesso

Conhecer o que uma função de banco de dados faz é fundamental se você irá apreciar possíveis vetores de ataque. Primeiro, você precisa controlar o acesso aos dados concedendo e revogando permissões.

Funções, e concessão de direitos e privilégios

O quão segura é uma função comum com direitos e privilégios padrão? A conta do usuário pode ser criada com um dos seguintes comandos:

  • A instrução SQL CREATE USER
  • A instrução SQL CREATE ROLE
  • O utilitário de linha de comandos Postgres createuser

Esses três métodos de criação de contas de usuário se comportam de maneira diferente, e resultam em direitos e privilégios padrão drasticamente diferentes.

Para uma função comum, o usuário típico pode:

  • Acessar qualquer banco de dados se o cluster de dados usar a política de autenticação padrão conforme descrito em pg_hba.conf.
  • Criar objetos no esquema PUBLIC de qualquer banco de dados que o usuário puder acessar.
  • Criar objetos de sessão (temporários) em sessões temporárias, como schema pg_temp_?
  • Alterar parâmetros de tempo de execução.
  • Criar funções definidas pelo usuário.
  • Executar funções definidas pelo usuário criadas por outros usuários no esquema PUBLIC (desde que eles interajam somente com objetos aos quais o usuário obteve privilégios concedidos para acessar).

É importante saber o que o usuário tem permissão para fazer, mas é igualmente importante entender as atividades que o usuário comum não pode fazer por padrão. Usuários comuns não podem:

  • Criar um banco de dados ou um esquema.
  • Criar outros usuários.
  • Acessar objetos criados por outros usuários.
  • Efetuar login (aplica-se somente à instrução CREATE ROLE).

Direitos e privilégios de superusuários

Apesar de um usuário comum não poder executar os direitos e privilégios definidos como recursos de superusuário, o usuário comum ainda pode causar um pouco de sofrimento com direitos e privilégios padrão.

Esta seção discute os vetores de ataque que o usuário comum pode manipular.

Acessando objetos

Uma prática extremamente comum e insegura ocorre quando o PostgreSQL é usado como o back end para um servidor da Web. O desenvolvedor cria o usuário comum desejando somente realizar aqueles comandos que manipulam os dados usando os comandos INSERT, UPDATE, e DELETE. Porém, ações não autorizadas são possíveis porque o esquema PUBLIC é aberto a todos. O usuário pode, por exemplo, fazer mineração de dados nessas tabelas. É até mesmo possível modificá-los incluindo regras e acionadores, salvando dados em tabelas localizadas no esquema PUBLIC, que podem então ser colhidos.

Lembre-se, uma conta de usuário comprometida pode fazer qualquer coisa que deseje aos objetos que possui.

Contornar esta ameaça é fácil: não deixe que a conta de usuário comum possua ou crie nada. A Lista 1 mostra como assegurar uma tabela.

Lista 1. Assegurando uma tabela
postgres=# SET SESSION AUTHORIZATION postgres;
SET
postgres=# CREATE ROLE user1 WITH LOGIN UNENCRYPTED PASSWORD '123';
CREATE ROLE
postgres=# CREATE SCHEMA user1 CREATE TABLE t1(i int);
CREATE SCHEMA
postgres=# INSERT INTO user1.t1 VALUES(1);
INSERT 0 1
postgres=# GRANT USAGE ON SCHEMA user1 TO user1;
GRANT
postgres=# SELECT I FROM user1.t1;
 i
---
 2
(1 row)

postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=> SELECT I FROM user1.t1;
ERROR:  permission denied for relation t1
postgres=> SET SESSION AUTHORIZATION postgres;
SET
postgres=# GRANT SELECT ON user1.t1 TO user1;
GRANT
postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=> SELECT I FROM user1.t1;
 i
---
 2
(1 row)

A Lista 2 demonstra interdição de acesso ao esquema PUBLIC.

Lista 2. Evitando que o user1 da função crie quaisquer entidades
postgres=> SET SESSION AUTHORIZATION postgres;
SET
postgres=# REVOKE ALL PRIVILEGES ON SCHEMA PUBLIC FROM user1;
REVOKE
postgres=# SET SESSION AUTHORIZATION user1;
SET

A mensagem de erro "ERRO:  
permissão negada para user1 do esquema" significa que esta medida defensiva funciona:

postgres=> CREATE TABLE X();
ERROR:  permission denied for schema user1

Acessando objetos sob o controle de outros usuários

Este vetor de ataque, mostrado na Lista 3 abaixo, assume que o usuário tem acesso ao esquema PUBLIC; por exemplo, GRANT USAGE ON SCHEMA PUBLIC TO user1. Ele funciona sob as seguintes suposições:

  • Todos os usuários tem, por padrão, permissão para se conectar a qualquer banco de dados no cluster.
  • Clusters de postura permitem aos usuários a capacidade de criar e manipular todas as entidades no esquema PUBLIC.
  • Uma conta de usuário comum tem o direito de acessar catálogos do sistema. Caso contrário, a conta do usuário não pode funcionar adequadamente (intrínseco ao comportamento do servidor PostgreSQL).
Lista 3. Reunindo informações sobre uma tabela
postgres=> SELECT * FROM user1.t2;
ERRO:  permissão negada para relação t2
postgres=> inserir nos valores de user1.t2 (10);
ERRO:  permissão negada para relação t2
postgres=>
postgres=> \d
        Lista de relações
 Esquema | Nome | Tipo  |  Proprietário
--------+------+-------+----------
 user1  | t1   | tabela | postgres
 user1  | t2   | tabela | postgres
(2 linhas)

postgres=> \d t?
        Tabela "user1.t1"
 Coluna |  Tipo   | Modificadores
--------+---------+-----------
 i      | número inteiro |

        Tabela "user1.t2"
 Coluna |  Tipo   | Modificadores
--------+---------+-----------
 i      | número inteiro |

Apesar de não ser possível acessar a tabela, o usuário ainda pode reunir informações sobre ela.

A Lista 4 mostra a conta de usuário user1 obtendo uma lista de contas de usuário e suas respectivas propriedades, também. O usuário comum não pode acessar as próprias senhas.

Lista 4. Obtendo propriedades de contas de usuário
postgres=> select * from pg_user;
 usename | usesysid | usecreatedb | usesuper | usecatupd | passwd | valuntil | useconfig
----------+----------+-------------+----------+-----------+----------+----------
postgres | 10 | t | t | t | ******** | |
 user1 | 18770 | f | f | f | ******** | |
(2 rows)

Todos os usuários possuem a habilidade padrão de aprender as definições e o esquema do cluster.

A Lista 5 mostra um script que reúne informações sobre o esquema de definição inteiro do cluster por meio de consulta dos catálogos. Os catálogos do sistema podem ser modificados, ou "raqueados", pelo superusuário, mitigando assim esta ameaça.

Lista 5. Extraindo definições globais do cluster
#!/bin/bash
psql mydatabase << _eof_
set search_path=public,information_schema,pg_catalog,pg_toast;
\t
\o list.txt
SELECT n.nspname||'.'||c.relname as "Table Name"
FROM pg_catalog.pg_class c
 JOIN pg_catalog.pg_roles r ON r.oid = c.relowner
 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','')
ORDER BY 1;
\q
_eof_

for i in $( cat list.txt ); do
 psql -c "\d $i"
done

Criando e acessando funções definidas pelo usuário

Funções são confiáveis ou não-confiáveis. Linguagens processuais confiáveis executam instruções dentro do contexto do banco de dados, como criação de tabelas, índices, inclusão ou remoção de dados, etc. Linguagens procedurais não confiáveis além dos recursos confiáveis, são capazes de afetar o mundo real também, como a lista de conteúdo de um diretório, criação, ou exclusão de arquivos, chamada de processos do sistema e mesmo criação de conexões de soquete para outros hosts.

Lista 6. Incluindo linguagens procedurais em um banco de dados e restaurando acesso ao user1
postgres=# create language plpgsql;
CREATE LANGUAGE
postgres=# create language plperlu;
CREATE LANGUAGE
postgres=# create language plperl;
CREATE LANGUAGE
postgres=> SET SESSION AUTHORIZATION postgres;
SET
postgres=# GRANT USAGE ON SCHEMA PUBLIC TO user1;
GRANT
Lista 7. Linguagens procedurais confiáveis versus não confiáveis
postgres=# select lanname as language, lanpltrusted as trusted from pg_language;
 language | trusted
----------+---------
 internal | f
 c        | f
 sql      | t
 plperlu  | f
 plperl   | t
(5 rows)

Diferentemente das tabelas, a conta de usuário não necessita de permissões especiais ao chamar a função de alguma outra pessoa, mesmo se elas foram criadas pelo superusuário.

Lista 8. Chamando uma função de superusuário
postgres=# SET SESSION AUTHORIZATION postgres;
SET
postgres=# CREATE OR REPLACE FUNCTION public.f1 (
postgres(# OUT x text
postgres(# ) AS
postgres-# $body$
postgres$# select 'hello from f1()'::text;
postgres$# $body$
postgres-# LANGUAGE SQL;
CREATE FUNCTION
postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=>
postgres=> SELECT * FROM f1();
 x
-----------------
 hello from f1()
(1 row)

A função na Lista 9 abaixo foi criada pelo superusuário usando plperlu. Ela retorna o conteúdo do diretório; user1 pode chamar esta função. Um usuário comum pode chamar ambas as funções, confiáveis e não confiáveis. O melhor método para mitigar esta ameaça é negar o acesso à função revogando o privilégio.

Lista 9. Explorando funções por um usuário autorizado
postgres=> SET SESSION AUTHORIZATION postgres;
SET
postgres=# CREATE OR REPLACE FUNCTION public.f2 (
postgres(# OUT x text
postgres(# ) AS
postgres-# $body$
postgres$# # emite conteúdo do diretório-raiz em saída padrão
postgres$# # observe o uso das aspas simples
postgres$# $a = `ls -l / 2>/dev/null`;
postgres$# $message = "\nAqui está a lista de diretórios\n".$a; 
postgres$# return $message;
postgres$# $body$
postgres-# LANGUAGE PLPERLU;
CREATE FUNCTION
postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=> SELECT * FROM f2();
 x
----------------------------------------------------------------------------

 Aqui está a lista de diretórios
 total 120
 drwxr-xr-x 2 root root 4096 Aug 29 07:03 bin
 drwxr-xr-x 3 root root 4096 Oct 11 05:17 boot
 drwxr-xr-x 3 root root 4096 Nov 26 2006 build
 lrwxrwxrwx 1 root root 11 Aug 22 2006 cdrom -> media/cdrom
 drwxr-xr-x 15 root root 14960 Oct 12 07:35 dev
 drwxr-xr-x 118 root root 8192 Oct 12 07:36 etc
(1 row)
Lista 10. Assegurando o user1 e o grupo PUBLIC
postgres=# SET SESSION AUTHORIZATION postgres;
SET
postgres=# REVOKE ALL ON FUNCTION f2() FROM user1, GROUP PUBLIC;
REVOKE
postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=> SELECT * FROM f2();
ERROR: permission denied for function f2
postgres=>

A Lista 11 envolve reunião de inteligência.

Lista 11. Obtendo o código de origem da função
postgres=> SET SESSION AUTHORIZATION user1;
SET
postgres=> select prosrc as "function f3()" from pg_proc where proname='f3';

 function f3()
---------------
# emite o conteúdo do diretório-raiz na saída padrão 
# observe o uso das aspas simples 
$a = `ls -l / 2>/dev/null`;
 $message = "\nAqui está a lista de diretórios\n".$a;
 return $message;
(1 row)

Para ocultar o código de origem:

  • Escreva a sua função como um módulo em seu ambiente de linguagem nativa (C, Perl, Python, etc.) e armazene-a no disco rígido do host. Depois crie uma função definida pelo usuário abstrata em PostgreSQL que chame o módulo.
  • Considere gravar o código de origem em uma tabela e dinamicamente criar sua função conforme for necessário.
  • Grave sua função definida pelo usuário em outro banco de dados no cluster, que é então chamada por uma conta de usuário autorizada usando o módulo dblink .

Usando o security definer

O security definer executa a função com os privilégios do usuário que a criou. Assim, um usuário pode acessar uma tabela que, sob circunstâncias normais, está indisponível.

Por exemplo, como mostrado na Lista 12, uma tabela com duas colunas é criada no esquema Postgres pelo postgres do superusuário. O usuário comum, user1, invocará uma função usando o parâmetro security definer e obterá um valor com base em um valor de entrada.

Lista 12. Criando uma tabela e uma função
postgres=# SET SESSION AUTHORIZATION postgres;
SET
postgres=# CREATE TABLE postgres.t4(x serial,y numeric);
NOTICE: CREATE TABLE will create implicit sequence "t4_x_seq" for serial column "t4.x"
CREATE TABLE
postgres=# INSERT INTO postgres.t4(y) VALUES (random()::numeric(4,3));
INSERT 0 1
postgres=# INSERT INTO postgres.t4(y) VALUES (random()::numeric(4,3));
INSERT 0 1
postgres=# INSERT INTO postgres.t4(y) VALUES (random()::numeric(4,3));
INSERT 0 1
postgres=# INSERT INTO postgres.t4(y) VALUES (random()::numeric(4,3));
INSERT 0 1
postgres=# INSERT INTO postgres.t4(y) VALUES (random()::numeric(4,3));
INSERT 0 1
postgres=# CREATE OR REPLACE FUNCTION public.f4 (
postgres(# IN a int,
postgres(# OUT b numeric
postgres(# ) RETURNS SETOF numeric AS
postgres-# $body$
postgres$# select y from postgres.t4 where x=$1 limit 1;
postgres$# $body$
postgres-# LANGUAGE SQL SECURITY DEFINER;
CREATE FUNCTION

A Lista 13 mostra que a conta de usuário user1 agora pode acessar as informações desejadas.

Lista 13. Função não-privilegiada acessando uma tabela com uma chamada de função
postgres=# SET SESSION AUTHORIZATION user1;
SET
postgres=> SELECT b as "my first record" FROM f4(1);
 my first record
-----------------
 0.379
(1 row)

postgres=> SELECT b as "my second record" FROM f4(2);
 my second record
------------------
 0.200
(1 row)

Invadindo a senha do PostgreSQL

A administração de senha efetiva é fundamental para a segurança em um DBMS. É função do DBA impor uma política de senha aprovada. Uma senha deve consistir em caracteres alfanuméricos escolhidos aleatoriamente que não tenham um padrão discernível. A prática comum dita que as senhas possuem pelo menos seis caracteres e são mudadas frequentemente.

Contas e senhas de usuário do PostgreSQL

A política de segurança da conta de usuário do PostgreSQL é centrada nos comandos SQL que criam e administram a conta do usuário:

  • CREATE ROLE
  • ALTER ROLE
  • DROP ROLE

As seguintes instruções SQL pertencem ao antigo estilo de administração de conta de usuário (apesar de válido, você deve usar a técnica mais nova de gerenciamento de usuários como funções):

  • CREATE GROUP
  • ALTER GROUP
  • DROP GROUP
  • CREATE USER
  • ALTER USER
  • DROP USER

As senhas são armazenadas como descriptografadas e criptografadas. Senha descriptografadas são armazenadas abertamente e podem ser lidas pelo superusuário. A senha criptografada envolve a geração e armazenamento de seu hash MD5, que não pode ser lido. Alguém valida a senha no momento do login ao executar hash e compará-la com o que já foi armazenado no cluster de dados.

Abaixo estão algumas chamadas de exemplo que criam e administram a senha:

  • Uma conta é criada sem uma senha:

    CREATE ROLE user1 WITH LOGIN;

  • Uma conta é criada com uma senha descriptografada:

    CREATE ROLE roger WITH LOGIN UNENCRYPTED PASSWORD '123'

  • Uma conta é alterada e uma senha criptografada é designada a ela:

    ALTER ROLE user1 WITH ENCRYPTED PASSWORD '123'

A execução de uma consulta SQL pelo superusuário em relação à tabela de catálogos pg_shadow retorna o nome da conta do usuário e sua senha. A Lista 14 mostra o código.

Lista 14. Obtendo a senha de um usuário do catálogo
postgres=# select usename as useraccount,passwd as "password" from pg_shadow where
length(passwd)>1 order by usename;

 useraccount | password
-------------+-------------------------------------
 user1 | md5173ca5050c91b538b6bf1f685b262b35
 roger | 123
(2 rows)

A Lista 15 mostra como é possível gerar o hash MD5 para user1 com a senha 123.

Lista 15. Gerando uma senha MD5
postgres=# select 'md5'||md5('123user1') as "my own generated hash",
                  passwd as "stored hash for user1"
           from pg_shadow where usename='user1';

 my own generated hash | stored hash for user1
-------------------------------------+-------------------------------------
 md5173ca5050c91b538b6bf1f685b262b35 | md5173ca5050c91b538b6bf1f685b262b35
(1 row)

Pronto para outro susto? Existem alguns poucos mecanismos dentro do PostgreSQL que podem impor uma política de senha blindada.

As possíveis limitações de segurança incluem:

  • O superusuário não pode impor um número mínimo de caracteres a ser usado para a senha.
  • Apesar de haver um parâmetro padrão nas definições da configuração para como a senha deva ser armazenada (descriptografada ou criptografada com um hash MD5), o usuário não pode ser forçado usar um métodos de armazenamento particular pelo superusuário.
  • Não existe nenhum mecanismo que imponha um tempo de vida à conta do usuário.
  • O mecanismo que controla o tempo de vida efetivo da senha da conta do usuário se torna irrelevante quando o método de conexão não é PASSWORD ou MD5 no arquivo de configuração de autenticação de cliente do cluster, pg_hba.conf.
  • Os parâmetros de tempo de execução do usuário que são alterados pela instrução ALTER ROLE e que foram configurados pelo superusuário ou pelas definições de configuração estabelecidas por padrão no arquivo postgresql.conf, podem ser alterados pelo proprietário da conta do usuário à vontade.
  • Renomear uma conta de usuário limpa sua senha se ela foi criptografada.
  • Não é possível controlar quem fez as mudanças nas contas de usuário ou quando essas mudanças ocorreram.

Uma arquitetura agressiva com edição cuidadosa dos catálogos do sistema podem recompensar o DBA vigilante.

Devido ao fascinante potencial para danos, as limitações de segurança das contas e senhas de usuário valem outro artigo separado.

Invadindo a senha

Impor uma senha forte é uma meta digna, mas simplesmente não há como julgar sua força até que alguém a invada. A invasão de utilitários se baseia em duas abordagens, como a seguir.

Força bruta
O teste metódico do hash. Ele começa com algumas letras, aumentando em comprimento à medida que o ataque continua. Este método é recomendado para testar senhas curtas.
Ataques de dicionário
Usa uma abordagem de engenharia social. Um dicionário de palavras, usado pelo utilitário de invasão, é o ponto inicial. Depois disso, combinações dessas palavras são geradas e testadas em relação ao hash capturado. Este ataque tira vantagem da crença errônea de que uma cadeia de caracteres longa que consista em uma combinação mnemônica de cadeias e caracteres é mais segura do que um comprimento um pouco mais curto de cadeias e caracteres escolhidos aleatoriamente.

Dependendo da força da senha e do hardware usado, a invasão pode ocorrer em alguns poucos segundos até vários meses.

Os DBAs estão interessados em identificar senhas com menos de seis caracteres de comprimento.

O utilitário da linha de comandos MDCrack usa a força bruta para testar a senha. Este binário Windows funciona bem em Linux sob Wine.

Inserir wine MDCrack-sse.exe --help retorna os comutadores de configuração. Alguns são mostrados abaixo:

Usage: MDCrack [options...] --test-hash|hash
       MDCrack [options...] --bench[=PASS]
       MDCrack [options...] --resume[=FILENAME]|--delete[=FILENAME]
       MDCrack [options...] --help|--about

A chamada de linha de comandos mais simples é wine MDCrack-sse.exe --algorithm=MD5 --append=$USERNAME $MD5_HASH, em que $USERNAME é o nome do usuário e $MD5_HASH é o hash MD5 na tabela de catálogos pg_shadow.

MDCrack pode executar em modo de sessão, como a seguir, assim é possível parar uma operação de invasão e continuar posteriormente.

Lista 16. MDCrack executando em modo de sessão
# iniciar sessão
wine MDCrack-sse.exe --algorithm=MD5 --append=$USERNAME $MD5_HASH\
 --session=mysessionfile.txt

# continuar o uso do último modo de sessão
wine MDCrack-sse.exe --algorithm=MD5 --append=$USERNAME $MD5_HASH\
 --resume=mysessionfile.txt

O conjunto de caracteres padrão é abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. Você poderia terminar com um processo imenso se a senha candidata incluísse um caractere que não fizesse parte do conjunto de caracteres definido como padrão. É possível mudá-lo para qualquer combinação de caracteres alfanuméricos que desejar. Por exemplo, você pode desejar incluir caracteres de controle e pontuação.

O ajuste do conjunto de caracteres é feito na linha de comandos. A variável $CHARSET representa o conjunto real de caracteres que será usado:

wine MDCrack-sse.exe --algorithm=MD5 --append=$USERNAME $MD5_HASH --charset=$CHARSET

O exemplo abaixo é uma chamada para violar uma senha do Postgres de 123. Ignorar os três primeiros caracteres fornece a você o valor hash MD5 md5173ca5050c91b538b6bf1f685b262b35. É possível determinar a senha com a seguinte chamada (dica: grep para a cadeia de caracteres Collision found). Esta invasão leva aproximadamente 0,32 segundos:

wine MDCrack-sse.exe --algorithm=MD5 --append=user1 173ca5050c91b538b6bf1f685b262b35\
| grep "Collision found"

A Lista 17 demonstra a invasão da senha no sistema catalog pg_shadow.

Lista 17. Invadindo a senha
wine MDCrack-sse.exe --algorithm=MD5 --append=user1 \
`psql -t -c "select substring(passwd,4) from pg_shadow where usename='user1';"` \
| grep "Collision found"

Modelos de autenticação

Agora que você viu o que pode dar errado, é hora de explorar o que você pode fazer para fazer as coisas certas. A autenticação é um assunto vasto, sendo assim, somente o básico será abordado aqui.

Sob o guarda-chuva "autenticação", existem muitos significados de controle de acesso para o cluster Postgres:

  • Soquetes de domínio UNIX
  • Autenticação de servidor Ident
  • Autenticação de servidor LDAP
  • PAM
  • Kerberos
  • SSL

Soquetes de domínio UNIX

Um soquete de domínio UNIX é um canal de comunicação bidirecional que remonta um arquivo de muitos aspectos. O servidor cria o soquete de domínio que está aguardando por clientes para abrir o arquivo com o sistema de arquivos. Um soquete de domínio PostgreSQL típico é mostrado abaixo.

Lista 18. Soquete de domínio típico
robert@wolf:~$ ls -la /tmp|grep PGSQL
srwxrwxrwx 1 robert robert 0 2007-10-15 12:47 .s.PGSQL.5432
-rw-------  1 robert robert   33 2007-10-15 12:47 .s.PGSQL.5432.lock

Observe que o número da porta está anexado ao nome do arquivo. Reconfigurar o servidor para uma porta TCP/IP diferente também altera o nome do soquete do domínio.

Três parâmetros no arquivo de configuração postgresql.conf controlam as permissões para um soquete de domínio:

  • unix_socket_directory (o arquivo PATH)
  • unix_socket_group (o grupo de usuários)
  • unix_socket_permissions (assume como padrão 0777)

O local do do soquete de domínio varia de acordo com a distribuição Linux:

  • O código de origem PostgreSQL instala e coloca o soquete no diretório /tmp.
  • O BSD localiza o soquete no diretório /tmp.
  • Os derivativos RedHat localizam o soquete no diretório /tmp.
  • Os derivativos Debian localizam o soquete em /var/run/postgresql com permissões somente para o postgresqlaccount.

Existem algumas coisas estranhas sobre soquetes de domínio. Considere as implicações do seguinte exemplo.

Sudo

sudo é um comando poderoso com muitas possíveis configurações que permitem aos usuários executar programas com os privilégios de segurança de outro usuário (normalmente o superusuário ou raiz). Similar ao comando do Windows runas.

Um cluster é criado no diretório inicial de robert (superusuário) com uma autenticação de confiável. Na inicialização do servidor, porém, as permissões de soquete de domínio permitem login, exceto robert. O usuário robert efetua login com TCP, mas é recusado no soquete de domínio. Porém, robert pode efetuar login através de um soquete de domínio após efetuar sudopara nobody.

Este exemplo mostra a versatilidade das permissões de arquivos, mitigando os danos causados por um cracker que se torne superusuário.

Lista 19. Permissões
robert@wolf:~$ initdb -A trust -U postgres ~/data

robert@wolf:~$ pg_ctl -D ~/data/ -l ~/logfile.txt \
-o "-c unix_socket_permissions=007 -c unix_socket_directory=/tmp" start
server starting

robert@wolf:~$ psql -h localhost -U postgres -c "select 'superuser:this works' as msg"
         msg
----------------------
 superuser:this works
(1 row)

robert@wolf:~$ psql -h /tmp -U postgres -c "select 'superuser:this fails' as msg"
psql: não foi possível conectar-se ao servidor: Permissão negada
        O servidor está executando localmente e aceitando
        conexões no soquete de domínio Unix "/tmp/.s.PGSQL.5432"?
robert@wolf:~$ sudo su nobody
[sudo] password for robert:

$ psql -h localhost -U postgres -c "select 'nobody:this works' as msg"
        msg
-------------------
 nobody:this works
(1 row)


$ psql -h /tmp -U postgres -c "select 'nobody:this still works' as msg"
           msg
-------------------------
 nobody:this still works
(1 row)

Ident

O servidor Ident responde a uma simples pergunta: Qual usuário iniciou a conexão que sai da sua porta X e se conecta à minha Y? No contexto de um servidor PostgreSQL, é informado o DBMS da Identidade da conta do usuário que está fazendo uma tentativa de login. O PostgreSQL então obtém essa resposta e permite ou nega permissão para login seguindo um conjunto de regras configurado pelo DBA nos arquivos de configuração apropriados.

O mecanismo de autenticação do servidor Ident do PostgreSQL funciona mapeando as contas de usuário do PostgreSQL para as contas de usuário do UNIX usando o servidor Ident do próprio host.

Os exemplos a seguir assumem que todas as conta de usuário do UNIX foram mapeadas no PostgreSQL para poder efetuar login em qualquer banco de dados, desde que eles usem o mesmo nome de conta no PostgreSQL. O login falha se o nome de usuário do UNIX não existir como uma conta de usuário no servidor PostgreSQL, ou se uma tentativa for feita para efetuar login usando outro nome de conta de usuário do PostgreSQL.

~Suponha que você tenha se conectado por meio de SSH no host: ssh -l robert wolf.

Lista 20. Um login falho e um bem-sucedido
robert@wolf:~$ psql -U robert robert
Bem-vindo ao psql 8.2.4, o terminal interativo do PostgreSQL.

Digite:  \copyright para termos de distribuição
       \h para ajuda com comandos SQL
       \? para ajuda com comandos psql
       \g ou terminar com ponto e vírgula para executar consulta
       \q para encerrar

robert@wolf:~$ psql -U postgres robert
psql: FATAL:  Autenticação Ident falhou para usuário "postgres"

-- Isto funciona, su para se tornar o postgres da conta do usuário UNIX

O PostgreSQL usa dois arquivos para administrar e controlar todas as sessões de login para usuários que foram autenticados pelo servidor Ident:

pg_hba.conf
Controla o acesso através de registros que são definidos em uma única linha.
pg_Ident.conf
Entra em ação quando o serviço Ident é usado como o autenticador da conta do usuário. Por exemplo, o METHOD é identificado como Ident no arquivo pg_hba.conf.
Lista 21. Exemplos de configuração simples
Exemplo 1: 
Uma conexão LOCALHOST impõe que a conta unix robert acesse o banco de dados 
robertexclusivamente. Não existe autenticação nos soquetes de domínio UNIX.
(pg_hba.conf)
# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD    OPTION
  host    all         all         127.0.0.1/32        Ident     mymap
  local   all         all                             trust
(pg_Ident.conf)
# MAPNAME     Ident-USERNAME    PG-USERNAME
  mymap       robert            robert


Exemplo 2: 
Uma conexão do soquete de domínio impõe que a conta unix robert acesse qualquer banco
de dados como conta pg robert; 
postgres de conta unix podem acessar qualquer banco de dados como usuário robert.
(pg_hba.conf)
# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD    OPTION
  local   all         all                             Ident     mymap
  host    all         all         127.0.0.1/32        trust

(pg_Ident.conf)
# MAPNAME     Ident-USERNAME    PG-USERNAME
  mymap       robert            robert
  mymap       postgres          robert


Exemplo 3: 
Uma conexão do soquete de domínio impõe que a conta unix pode se conectar a qualquer
banco de dados com seu homônimo de banco de dados postgres usando a 
palavra-chave "sameuser".  
pg_Ident.conf não é necessariamente aqui. 
Conexões do host local através de TCP-IP são rejeitadas.

(pg_hba.conf)
# TYPE  DATABASE                USER        CIDR-ADDRESS          METHOD    OPTION
  local   template0,template1    all                             Ident     sameuser
  host    all                    all         127.0.0.1/32        reject

Ex4: 
(todos os usuários podem se conectar com seus próprios nomes de usuário somente 
aos bancos de dados postgres e robert)

(pg_hba.conf)
# TYPE  DATABASE                USER        CIDR-ADDRESS          METHOD    OPTION
  local   template0,template1    all                             Ident     sameuser

Lembre-se das seguintes advertências:

  • As mudanças de configuração tomam efeito assim que você recarrega os arquivos, como pg_ctl -D mycluster reload.
  • Várias definições de configuração podem causar comportamento temperamental. Procure por mensagens de configuração falhas no log.
  • Ident foi projetado e implementado quando as próprias máquinas foram consideradas seguras. Qualquer servidor remoto que procure autenticação deve ser considerado suspeito.
  • O servidor Ident é usado somente para autenticar conexões de host local.

Criptografia de dados

Existem muitas maneiras pelas quais você pode se expor inadvertidamente a um cracker dentro de uma intranet.

Vamos dar uma sondada. Suponha que você execute o seguinte comando no seu host local, 192.168.2.64: tcpdump -i eth0 -X -s 3000 host 192.168.2.100 and port 5432.

Em um host remoto, 192.168.2.100, você se conecta ao PostgreSQL do host local, que já está atendendo na porta 5432: psql -h 192.168.2.64 -p 5432 -U postgres postgres. Agora altere a senha da sua conta de superusuário, postgres: ALTER USER postgres WITH ENCRYPTED PASSWORD 'my_new_password';.

Lista 22. Discernindo a senha em um dump de dados sondado
16:39:17.323806 IP wolf.56336 > laptop.postgresql: P 598:666(68) ack 470 win 3068
<nop,nop,timestamp 9740679 9589666>
 0x0000: 4500 0078 4703 4000 4006 6d88 c0a8 0264 E..xG.@.@.m....d
 0x0010: c0a8 0240 dc10 1538 6a4f 7ada 6a71 e77c ...@...8jOz.jq.|
 0x0020: 8018 0bfc 1a9d 0000 0101 080a 0094 a187 ................
 0x0030: 0092 53a2 5100 0000 4341 4c54 4552 2055 ..S.Q...CALTER.U
 0x0040: 5345 5220 706f 7374 6772 6573 2057 4954 SER.postgres.WIT
 0x0050: 4820 454e 4352 5950 5445 4420 5041 5353 H.ENCRYPTED.PASS
 0x0060: 574f 5244 2027 6d79 5f6e 6577 5f70 6173 WORD.'my_new_pas
        0x0070:  7377 6f72 6427 3b00                      sword';.

Túneis SSH usando redirecionamento de porta

O redirecionamento de IP é uma tecnologia de tunelamento que redireciona pacotes da Internet de um host para outro. Ele permite que seus clientes PostgreSQL, como psql, pgadmin, e mesmo openoffice, se conectem ao servidor Postgres remoto com uma conexão SSH.

Considere as seguintes questões:

  • O que acontece se não existir nenhum cliente psql no servidor PostgreSQL remoto?
  • O que acontece se você precisar fazer upload ou download de dados entre sua estação de trabalho e o host remoto?
  • O que você faz quando precisa usar os clientes do banco de dados porque eles podem executar certas tarefas que o cliente psql também não pode fazer, ou que não pode fazer de jeito algum?
  • Como fazer o tunelamento de sua rede para que a sua equipe possa se conectar remotamente a um banco de dados protegido por um firewall?

Este exemplo conecta um cliente (host local) a um host remoto (192.168.2.100). Uma conexão com proxy na porta da estação de trabalho de 10000 é criada. O cliente, na conexão com a porta 10000, é redirecionado para o servidor PostgreSQL do host remoto, que está atendendo na porta 5432: ssh -L 10000:localhost:5432 192.168.2.100.

Incluir o comutador -g permite que outros hosts obtenham vantagem da sua conexão redirecionada, o que a torna uma rede privada virtual (VPN) instantânea para conexões Postgres: ssh -g -L 10000:localhost:5432 192.168.2.100.

Algumas advertências sobre tunelamento:

  • O cliente e o servidor do banco de dados têm a impressão de que estão se comunicando com seu próprio host local.
  • Lembre-se de configurar o arquivo pg_hba.conf para definir a autenticação correta para as conexões do host local usando TCP/IP.
  • Portas abaixo de 1024 são exclusivamente controladas pelo raiz.
  • Sessões de SSH necessitam de uma conta de usuário existente no servidor PostgreSQL/SSH.

Sessões criptografadas por SSL

Sessões criptografadas com PostgreSQL necessitam que o servidor seja compilado com o comutador --with-openssl . Os binários distro do Linux possuem essa função. Clientes como psql e pgadmin também possuem os recursos do requisito.

É possível especificar o servidor usando o utilitário de linha de comandos pg_config , como a seguir.

pg_config --configure

Para preparar o servidor PostgreSQL para sessões criptografadas:

  1. Crie uma chave de servidor auto-assinada (server.key) e um certificado (server.crt) usando a ferramenta de linha de comandos OpenSSL openssl.
    1. Crie a chave do servidor: openssl genrsa -des3 -out server.key 1024.
    2. Remova a passphrase openssl rsa -in server.key -out server.key.
    3. Crie um certificado auto-assinado para o servidor: openssl req -new -key server.key -x509 -out server.crt.
  2. Instale os dois arquivos, server.key e server.crt, no diretório do cluster de dados.
  3. Edite o arquivo postgresql.conf e configure o par nomeado: ssl = on.
  4. Reinicie o servidor.
    Lista 23. Conexão de sessão criptografada com SSL bem-sucedida
    robert@wolf:~$ psql -h 192.168.2.100 -U robert
    Bem-vindo ao psql 8.2.4, o terminal interativo do PostgreSQL.
    
    Digite:  \copyright para termos de distribuição
           \h para ajuda com comandos SQL
           \? para ajuda com comandos psql
           \g ou terminar com ponto e vírgula para executar consulta
           \q para encerrar
    
    Conexão SSL (código: DHE-RSA-AES256-SHA, bits: 256)
    
    robert=#

O servidor sempre testa a conexão primeiro para os pedidos de sessão criptografados. Porém, é possível controlar o comportamento do servidor editando o arquivo de autenticação pg_hba.conf. No lado do cliente, é possível controlar o comportamento padrão do cliente (psql) para o uso de uma sessão criptografada ou não por meio da definição da variável de ambiente PGSSLMODE.

Existem seis modos (dois novos modos são específicos da V8.4).

ModoDescrição
disableTentará somente conexões SSL descriptografadas.
allowPrimeiro tenta uma conexão descriptografada e, se não obtiver êxito, uma tentativa de conexão SSL é feita.
preferO oposto de allow; a primeira tentativa de conexão é SSL e a segunda é descriptografada.
requireO cliente tenta somente uma conexão SSL criptografada.
verify-caUma conexão SSL, e certificado de cliente válido assinado por um CA confiável.
Verify-fullUma conexão SSL, certificado de cliente válido assinado por um CA confiável, e o nome do host do servidor correspondente ao nome do host do certificado.

Por exemplo: export PGSSLMODE=prefer.

Certificados SSL

Autenticação SSL é quando o cliente e o servidor trocam certificados que foram assinados por um terceiro que tem credenciais inquestionáveis. Esse terceiro é conhecido como uma autoridade de certificação (CA). A conexão é recusada pelo servidor ou pelo cliente quando não recebe um certificado legítimo do outro.

Apesar de haver muitos detalhes, a configuração de uma autenticação no PostgreSQL usando certificados SSL é direta:

  1. Edite postgresql.conf, ssl=on.

    A autenticação do lado do servidor precisa que os seguintes arquivos estejam em seu cluster de dados:

    • server.key
    • server.crt (que deve ser assinado por um CA)
    • root.crt (verifica a autenticação do cliente)
    • root.crl (lista de revogação de certificado, opcional)

    O arquivo root.crt contém uma lista de certificados CA aprovados. Deve haver um coleta inteira de certificados disponíveis para a sua distribuição particular, que você pode incluir.

    A arquivo root.crl é similar ao root.crt quanto ao fato de que contém uma lista de certificados assinados pelo CA. Porém, esses certificados são de clientes que tiveram o direito de conexão revogado. Um root.crl vazio não interferirá com o processo de autenticação.

    A autenticação do lado do cliente precisa que os seguintes arquivos estejam no diretório inicial do cliente, ~/.postgresql:

    • postgresql.key
    • postgresql.crt
    • root.crt (verifica a autenticação do servidor)
    • root.crl (lista de revogação de certificado, opcional)

    Assim como com o root.crt do servidor, arquivo do cliente, root.crt, contém uma lista de certificados que foram assinados por um terceiro CA respeitado. O último arquivo, root.crl, é opcional e é usado para revogar certificados do servidor.

    A obtenção de certificados requer que ambos, cliente e servidor, tenham enviado pedidos de certificado, client.csr e server.csr, ao CA. Os certificados somente podem ser criados após terem gerado suas próprias chaves privadas, como a seguir.

    openssl req -new -newkey rsa:1024 -nodes -keyout client.key -out client.csr
    openssl req -new -newkey rsa:1024 -nodes -keyout server.key -out server.csr

    Existe mais de uma maneira de executar o utilitário openssl para obter o que você precisa. Por exemplo, é possível colocar um tempo de vida neles, ou é possível gerá-los com certificados auto-assinados e eliminar a necessidade de um CA.

  2. Agora você tem três opções para gerar seus certificados de cliente e servidor. Você pode:
    • Obter client.csr e server.csr assinados por um CA respeitado.
    • Se tornar um CA usando o utilitário openssl perl CA.pl.
    • Criar certificados auto-assinados e inclui-los nos arquivos root.crt do servidor e do cliente, respectivamente.
  3. Abaixo está um conjunto de comandos abreviados para usar com o CA.pl. Consulte as man pages CA.pl para obter mais informações sobre pedidos de certificado.
    • CA.pl -newca (criar a nova CA)
    • CA.pl -newreq (criar um pedido de certificado com uma chave privada)
    • CA.pl -signreq (assinar o pedido de certificado pelo CA que você criou)

    Para os puristas do software livre, sempre há o http://www.cacert.org para certificados 'grátis'.

    Lista 24. Um certificado de exemplo
    -----BEGIN CERTIFICATE-----
    MIIC9TCCAl6gAwIBAgIJAMuhpY+o4QR+MA0GCSqGSIb3DQEBBQUAMFsxCzAJBgNV
    BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
    aWRnaXRzIFB0eSBMdGQxFDASBgNVBAMTC0NvbW1vbiBOYW1lMB4XDTA3MDIxMjEy
    MjExNVoXDTA3MDMxNDEyMjExNVowWzELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNv
    bWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIG
    A1UEAxMLQ29tbW9uIE5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKA4
    nX/eBKsPJI1DmtH2wdJE9uZf+IRMUWYrAEDL4F6NEuo2+BsIoOBKS/rrV77Itet9
    kduJCQ6k/z2ouAVb4muXpJALDjJpYBXt9wqZf+2p1n9dqDw1rCWBjXIdhOcA3DDv
    u0Ig1FUfm8GS97evxM5IJBECRnK/5JZroXCRSHcpAgMBAAGjgcAwgb0wHQYDVR0O
    BBYEFElEWNUCV+61itXp86czrDe35vjrMIGNBgNVHSMEgYUwgYKAFElEWNUCV+61
    itXp86czrDe35vjroV+kXTBbMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1T
    dGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQD
    EwtDb21tb24gTmFtZYIJAMuhpY+o4QR+MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
    AQEFBQADgYEAaFzbUmXcWVzqaVeEpZkNwF/eVh110qIUUxXGdeKZGNXIyK67GCUY
    SG/IFkZ/hrGLeqElLrdmU0mHd2Enq2IuvhxnsOVTTickjKospJvlHPYSumkXx0Xp
    zey9PhjLh1chpxNGTATKb8ET8YZvBRrDHl/EMPIjLd62iSR/ugFe8go=
    -----END CERTIFICATE-----
  4. Supondo que você gerou certificados auto-assinados, copie-os no local correto e edite root.crt.

    O certificado do cliente é salvo no root.crt do servidor e o certificado do servidor é alvo no root.crt do cliente.

  5. Monitore as mensagens de log na reinicialização do servidor para confirmar que tudo está configurado corretamente.

O comportamento padrão do servidor ainda usa criptografia. Isso pode ser desativado editando-se o par de nomes ssl_ciphers='NULL' em postgresql.conf e reiniciando o servidor. Considere sua decisão com cuidado; configurar ssl_ciphers para NULL efetivamente desativa a criptografia.


Conclusão

Neste artigo, você aprendeu alguns fundamentos sobre a proteção do servidor do seu banco de dados PostgresSQL. Existe muito mais material sobre este assunto, mas não é possível abordar muitos tópicos em um só artigo. Não há o suficiente sendo escrito sobre o PostgreSQL atualmente. Talvez, com um pouco da sua ajuda, possamos aprender mais sobre a segurança do PostgreSQL.


Download

DescriçãoNomeTamanho
Sample codeos-postgresecurity-listings_src_code.zip10KB

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=454006
ArticleTitle=Segurança Total em um Banco de Dados PostgreSQL
publish-date=12162009