Questões de Segurança em Engenharia de Software Trabalho II 1 Descrição geral Neste trabalho considera-se um serviço de palavras-passe escrito em Java, com código disponibilizado na forma de um projecto Eclipse. O código em questão tem algumas vulnerabilidades de segurança, bem como alguns “bugs” na sua funcionalidade. Pretende-se que: 1. Detecte as vulnerabilidades de segurança usando um auditor de código e elimine as mesmas com alterações ao código. 2. Feitas as alterações anteriores, que valide parte do código usando testes de software, em particular considerando critérios de partição de espaço de entrada e testes de mutação. Deverá entregar: 1. Um arquivo ZIP contento o projecto Eclipse modificado, incluı́ndo alterações ao código e testes que programou. 2. Um relatório abordando os vários aspectos detalhados nas próximas páginas. Posteriormente deverá apresentar o trabalho na aula, usando eventualmente também alguns “slides” com um sumário do trabalho desenvolvido. 2 Ferramentas a usar Veja o ficheiro SETUP.txt disponibilizado na página da disciplina para instruções de instalação. • Eclipse IDE – recomenda-se que instale uma versão da variante “Classic” de fresco; • Base de dados H2 – já incluı́da no projecto; • FindBugs + FindSecBugs para auditoria de código – siga as instruções de configuração em SETUP.txt. • contrast-rO0, biblioteca para deserialização segura de objectos Java – já incluı́da no projecto; • JUnit, biblioteca para escrita de testes de software – já parte do Eclipse; • JDBDT, biblioteca para suporte aos testes no que toca manuseamento e validação do conteúdo da base de dados – já incluı́da no projecto; • PITclipse, plug-in Eclipse para a ferramenta PIT de testes de mutação – siga as instruções de configuração em SETUP.txt. 3 3.1 Descrição do serviço de palavras-passe Arquitectura client programs ServerConnection Request Reply Server server side manager operations Manager database access InputChecker SHGenerator PasswordData DAO H2 database A arquitectura de software é ilustrada acima, sendo visı́vel a organização em camadas e referindo as principais classes Java. A documentação Javadoc pode ser encontrada em home/javadoc. • O sistema armazena informação numa base de dados H2. É usada uma única tabela chamada PASSWORDS, com campos LOGIN, SALT e HASH. A entrada para o login root é especial, no sentido de ser necessária para efeitos de autenticação nas camadas superiores da arquitectura. • Um objecto DAO (‘data access object”) medeia o acesso à base de dados, mapeando pedidos de operações em comandos SQL enviados à base de dados. Para interface com DAO são usados objectos PasswordData, que encapsulam o mesmo tipo de informação que a guardada na tabela PASSWORDS. • A classe Manager representa o gestor do sistema, respondendo a operações de modificação ou consulta de informação. O gestor verifica se as operações são válidas, e nesse caso, delega as alterações/consultas à base de dados em DAO. No seu funcionamento, Manager interage ainda com InputChecker para verificar a boa formação de identificadores de utilizadores e de palavraspasse, e com SHGenerator para gerar valores de “salt” e “hash” para palavras-passe. • O serviço de palavras-passe é exposto na rede por um servidor TCP/IP, instanciado pela classe Server. Um servidor fica à escuta de ligações cliente, estabelecidas usando a classe ServerConnection. A interacção cliente-servidor é feita via objectos Java serialisados para representar pedidos do cliente e respostas do servidor, Request e Reply respectivamente. 3.2 Uso No directório home/bin do projecto Eclipse encontra os seguintes scripts: • configure.sh – inicializa a base de dados. • server.sh <port> – inicia o servidor. • client.sh <host> <port> – inicia programa cliente. • dbconsole.sh – utilitário que lança a consola H2 para inspecionar a base de dados. • sah.sh <seed> <password> – utilitário que mostra o “salt” e o “hash” para uma palavra-passe, usando a “seed” dada para o gerador de números pseudo-aleatórios (poderá ser útil para gerar dados de teste). 4 Tarefas a realizar 4.1 Análise e correcção de vulnerabilidades 1. Execute o FindBugs, com o módulo FindBugsSec já acoplado ao FindBugs, e configurando apenas as opções de Security, Malicious code vulnerability, e Correctness. • Para configurar aceda às propriedades do projecto, secção FindBugs. • Para executar selecione src com o botão direito do rato e clique em Find Bugs. 2. Ignore os avisos de vulnerabilidade relacionados com “file system traversal” / uso de java.io.File. 3. Acerte os restantes pontos de vulnerabilidade. 4. Para cada vulnerabilidade, identifique no relatório o código vulnerável na versão original, as ameaças à segurança do sistema inerentes, e as modificações ao código operadas. • Nota: para as vulnerabilidades relacionadas com serialização de objectos Java, use as funcionalidades da biblioteca contrast-rO0 em modo “spot fix” (i.e., ao invés do “agent mode”). 4.2 4.2.1 Testes de software TestInputChecker A classe TestInputChecker deverá reunir os testes feitos à classe InputChecker, para validar os métodos isValidLogin e isValidPassword, usando uma aproximação baseada em “input space partitioning” (ISP). 1. Identifique primeiro no relatório: (a) Para cada um dos métodos, isValidLogin e isValidPassword, a escolha de caracterı́sticas e blocos correspondentes; (b) Os requisitos de teste derivados da escolha de caracterı́sticas/blocos, considerando o critério ECC (“Each Choice Coverage”) para isValidLogin e o critério PWC (“Pair-wise Coverage”) para isValidPassword; 2. Seguidamente: (a) Programe casos de teste (um @Test JUnit por caso de teste) que cubram os requisitos, identificados, e documente no relatório os requisitos cobertos por cada caso de teste. (b) Encontrou “bugs” ? Acerte o código! Documente os “bugs” e alterações ao código no relatório. (c) No final, execute os testes em modo de mutação usando o PIT, e verifique se há mutantes que sobrevivem. Programe testes adicionais se forem necessários, e faça referência a estes no relatório. Identifique também se encontrou mutantes funcionalmente equivalentes. 4.2.2 TestDAO A classe TestDAO deverá reunir os testes feitos à classe DAO. Os testes deverão validar o retorno dos métodos e também o seu efeito sobre a base de dados usando asserções δ do JDBDT. São já fornecidos alguns testes exemplo bem como outro código de suporte aos testes, em particular a inicialização da base de dados de teste. Os testes a considerar são os seguintes: 1. Para cada um dos métodos delete, insert, query e update : inclua dois testes, correspondentes ao seguintes dois casos: (a) utilizador em causa já existe na base de dados e (b) utilizador em causa não existe. 2. Dois testes adicionais: um para listLogins e outro para clearAllExceptRoot. 3. Encontrou “bugs” ? Acerte o código! Documente os “bugs” e alterações ao código no relatório. 4.2.3 TestServer A classe TestServer deverá reunir os testes de sistema feitos à classe Server, i.e., ao servidor no seu todo. Os testes deverão validar as respostas do servidor (Reply, sucesso ou falha) e novamente também o seu efeito sobre a base de dados usando asserções δ do JDBDT. São já fornecidos alguns testes exemplo bem como outro código de suporte aos testes; em particular a execução do servidor que iniciará automaticamente antes de qualquer teste. 1. Programe testes análogos aos descritos para a classe DAO (excepto query) na forma de pedidos ao servidor (Request). 2. Encontrou “bugs” ? Acerte o código! Documente os “bugs” e alterações ao código no relatório. 3. Execute os testes em modo de mutação. (a) Programe testes por forma a matar todos os mutantes que forem possı́veis na classe Manager, ignorando mutações sobre a classe Server em si. Ignore também mutações sobre o texto de objectos Reply, excepto para o método listLogins(). (b) Faça referência a estes testes adicionais no relatório e identifique também se encontrou mutantes funcionalmente equivalentes.