EA878:2009 2S:atividade 9

De DCA-Wiki

Contents

Objetivos

  • Familiarização com o processo de autenticação básico do HTTP (RFC2617)
  • Familiarização com o processo de codificação base64 (RFC3548)
  • Familiarização com chamada de sistema de criptografia em Unix
  • Implementação de mecanismo de autenticação no servidor HTTP em desenvolvimento

Introdução

Frequentemente temos a necessidade de controlar o acesso de terceiros aos recursos (arquivos) armazenados no webspace de um servidor web. Este controle de acesso pode ser feito de várias formas como, por exemplo, por usuário/senha, por nome de domínio, por endereço IP, etc. Nesta atividade nos restringiremos ao controle de acesso baseado na autenticação de um usuário por meio de senha. Um dos métodos mais utilizados para controlar o acesso aos arquivos em um servidor é colocando no diretório que se deseja proteger um arquivo especial (normalmente chamado de .htaccess) que fornece ao servidor informações sobre o controle de acesso aos arquivos daquele diretório.

Um arquivo .htaccess protege não só o diretório no qual se encontra, mas também todos os subdiretórios abaixo dele. Se o servidor percebe a existência de um .htaccess em qualquer um dos diretórios que fazem parte do caminho ao recurso solicitado, ele não envia diretamente o recurso ao cliente, mas somente um cabeçalho (de erro 401) acrescido de uma linha indicando a necessidade de autenticação (linha WWW-Authenticate). Supõe-se aqui que o cliente não ofereceu nenhuma informação de autenticação junto com a requisição do recurso. Observe que, caso haja mais de um .htaccess no caminho até o recurso, aquele mais próximo do recurso é que deve ser usado para o controle de acesso. Observe ainda que, se o recurso solicitado estiver protegido por .htaccess (existente em qualquer parte do caminho ao recurso), o servidor deve solicitar a senha antes mesmo de verificar se o recurso existe. Mesmo que tal recurso não exista, o servidor não deve deixar que o cliente saiba disso sem ter antes fornecido uma senha correta.

Ao receber o cabeçalho indicando a necessidade de autenticação, o cliente (browser) abre automaticamente uma janela de autenticação, solicitanto um nome de usuário e uma senha. Após serem digitadas pelo usuário, estas duas informações são agrupadas na forma usuário:senha, codificadas segundo o padrão base64 (RFC3548) (para evitar que eventuais caracteres especiais usados no nome ou senha sejam corrompidos no percurso) e enviadas junto com uma nova requisição ao servidor solicitando o mesmo recurso que foi solicitado antes.

Ao receber a nova requisição, agora completa com as informações de autenticação, o servidor deve decodificá-las (usando o mesmo padrão base64) e compará-las com as que possui em seu cadastro (o arquivo .htaccess deverá conter o caminho do arquivo com as senhas). Se as informações de usuário e senha conferirem, então o servidor pode enviar o recurso solicitado pela rede; caso contrário ele deve enviar um novo cabeçalho de erro 401 solicitando ao browser o envio de senha.

Esta é a forma de autenticação mais simples, conhecida por Basic Authentication. Há outra, chamada Digest Authentication, que evita que a senha seja enviada de forma aberta pela rede. Esta segunda não será utilizada nesta atividade. Maiores detalhes sobre a autenticação básica estão disponíveis na RFC2617.

Etapas da Basic Authentication

  • 1. O cliente requisita recurso sem enviar informações de autenticação.
  • 2. Se o recurso está protegido por .htaccess, o servidor responde ao cliente que o recurso possui controle de acesso e solicita o par usuário-senha:
       HTTP/1.1 401 Authorization Required
       ...
       ...
       WWW-Authenticate: Basic realm="Espaço Protegido 1"
       ...
       ...
  • 3. O cliente abre janela e requisita usuário e senha.
  • 4. O cliente codifica dados (usuário:senha) usando base64 e envia para servidor a mesma requisição anterior acrescida de uma linha com dados de autenticação:
       Authorization: Basic ZWNvbXA6bW9kX0FC  <-- esta parte final é o par usuário:senha codificado.
  • 5. O servidor decodifica os dados, faz a autenticação (confere usuário e senha) e envia recurso ao cliente se tudo estiver ok. Caso contrário, servidor envia mensagem de erro como na etapa 2.

Exemplo

Pedido do cliente (existe arquivo .htaccess no diretório controlado):

   GET /ea878/teste/controlado/segredo.html HTTP/1.1
   Host: azaleia.fee.unicamp.br
   User-Agent: Firefox 3.5.1
   Accept: text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, image/png, image/jpeg,
           image/gif;q=0.2, text/plain;q=0.8, text/css, */*;q=0.1

Resposta do servidor:

   HTTP/1.1 401 Authorization Required
   Date: Tue, 21 Sep 2009 11:51:21 GMT
   Server: Apache/1.3.9 (Unix)
   WWW-Authenticate: Basic realm="Espaço Protegido 1"
   Transfer-Encoding: chunked
   Content-Type: text/html X-Pad: avoid browser bug

Novo pedido do cliente, agora com autorização (após usuário ter digitado nome e senha):

   GET /ea878/teste/controlado/segredo.html HTTP/1.1
   Host: www.fee.unicamp.br
   User-Agent: Firefox 3.5.1
   Accept: text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, image/png, image/jpeg, 
           image/gif;q=0.2, text/plain;q=0.8, text/css, */*;q=0.1
   Accept-Language: en-us
   Accept-Encoding: gzip, deflate, compress;q=0.9
   Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66
   Authorization: Basic ZWNvbXA6bW9kX0FC

Geração do arquivo de senha no servidor

Para melhorar a segurança, o cadastro de usuários e senhas deverá ficar em um ou mais arquivos de senhas armazenados fora do webspace. Para simplificar a implementação, o caminho completo até um dos arquivos de senhas será o único conteúdo de cada .htaccess. Para cada usuário deveremos ter no arquivo de senhas especificado por .htaccess uma linha do tipo

               usuário:senha

que será usada na comparação dos dados que vieram pela rede.

Para evitarmos que as senhas possam ser conhecidas por quem tiver acesso ao arquivo, iremos armazená-las de forma criptografada, usando a função crypt( ) exemplificada no código abaixo.

   /* Compile com: gcc -o cripto cripto.c -lcrypt
   */
   #define _XOPEN_SOURCE
   #include <unistd.h>
   int main(int argc, char **argv)
   {
       if (argc < 3) exit(0);
       printf("\n%s\n\n", crypt(argv[1], argv[2]));
       return 0;
   }

Esta função é a utilizada pelo Unix para proteger suas senhas e ela transforma somente os primeiros oito bytes de argv[1] (a senha) em um conjunto de caracteres imprevisíveis, mas imprimíveis. Isto significa que não é preciso aplicar a codificação base64 no resultado de crypt( ) antes de armazenar no arquivo, pois ela não retorna valores binários arbitrários. Significa também que serão ignorados os bytes a partir do 9o que fizerem parte de argv[1].

O argumento argv[2] é um parâmetro de dois caracteres chamado salt cujo objetivo é modificar a forma de funcionamento interno do algoritmo de criptografia. Em nossa implementação vamos utilizar um valor único para ele em todos os casos: "aa". Observe que os primeiros 2 caracteres retornados por crypt( ) são exatamente estes dois caracteres do salt, mas podemos ignorar isso e considerá-los parte da senha cifrada. Por exemplo, se usarmos o programa cripto.c acima na senha feec com um salt aa, obtemos como saída a seqüência aahOcrXpNhyJU , que será a forma de armazenarmos a senha feec no arquivo de senhas.

Observe que no arquivo de senhas a parte usuário: da linha usuário:senha deverá estar armazenada de forma clara, isto é, não codificada e nem criptografada. Somente a parte senha deverá estar criptografada.

Para o servidor comparar a senha recebida pela rede com a que está no arquivo, será preciso que ele decodifique (base64) o par usuário:senha recebido, cifre somente a senha usando crypt( ), busque o nome do usuário no arquivo de senhas apontado por .htaccess e compare a senha que o acompanha com aquela retornada por crypt( ). A comparação se dará, portanto, no domínio das senhas cifradas, porque essa é uma forma mais segura e normalmente adotada em sistemas que usam autenticação de usuários. Se um mesmo usuário estiver cadastrado mais de uma vez dentro de um arquivo de senhas, deverá ser considerada somente a primeira ocorrência do usuário no arquivo.

Relatório

O relato no caderno de projeto deverá conter, no mínimo, os seguintes pontos:

  • código-fonte documentado (só com as funções que mudaram e/ou foram incluídas nesta atividade);
  • explicações detalhadas sobre as mudanças introduzidas no seu sistema por causa da autenticação, sobre as dificuldades enfrentadas e sobre pontos ainda pendentes;
  • documentação de três testes com erro, mas causados por situações distintas (usuário errado, senha errada, falta de senha etc); esta documentação deve incluir todas as informações que permitam o completo entendimento das condições em que os testes ocorreram: conteúdos dos arquivos de senhas e dos .htaccess envolvidos no teste, estado do webspace no momento dos testes etc;
  • documentação de três testes com sucesso e em diferentes profundidades do webspace, cada um com um arquivo .htaccess diferente; esta documentação deve incluir todas as informações que permitam o completo entendimento das condições em que os testes ocorreram: conteúdos dos arquivos de senhas e dos .htaccess envolvidos no teste, estado do webspace no momento dos testes etc.

Obs: os testes deverão ser feitos com base no webspace de testes que está disponível no arquivo testes.zip.

Ferramentas pessoais