Security and Usability in the HeadREST Language

Abstract

Tese de mestrado, Engenharia Informática (Arquitectura, Sistemas e Redes de Computadores) Universidade de Lisboa, Faculdade de Ciências, 2020Actualmente, observa-se o crescimento contínuo de serviços web, sem sinais de abrandar. As trocas de informação com estes serviços seguem diferentes padrões. De entre os muitos padrões utilizados, destaca-se o REST (REpresentational State Transfer). O REST é um estilo arquitectural muito utilizado actualmente. Neste estilo arquitectural as operações e propriedades do protocolo HTTP, sobre o qual o World Wide Web funciona, são aproveitadas para realizar as interacções de clientes com serviços web. Em REST, o elemento basilar são os recursos, que correspondem a pedaços de informação que podem ser referenciados por um identificador. Cada recurso tem uma, ou várias, representações, que podem ter diferentes formatos, e que podem mudar na sequência de operações executadas sobre o mesmo. Um serviço web que adere ao estilo arquitectural REST é chamado de serviço REST. Para programar clientes de um serviço REST é fundamental que esteja disponível uma boa documentação da sua API, com especificações claras das suas operações e dos dados trocados nestas operações entre os clientes e o serviço. No desenvolvimento deste tipo de serviços são utilizadas linguagens de descrição de interfaces, tal como a OpenAPI Specification, o RAML ou a API Blueprint. Estas linguagens permitem especificar formalmente as operações suportadas por um serviço REST e oferecem a capacidade de documentar os dados que são trocados durante as interacções com o serviço. Apesar da sua popularidade, estas linguagens de especificação têm um poder expressivo limitado. Uma das limitações é que não terem capacidade para descrever com precisão o comportamento das diferentes operações. Numa tentativa de endereçar estas limitações, tem vindo a ser desenvolvida a linguagem HeadREST. A linguagem tem um sistema de tipos refinados que permite restringir os valores admissíveis de um tipo, e portanto descrever com mais rigor os tipos dos dados trocados num serviço REST. Para permitir especificar com precisão as operações de um serviço REST, a linguagem HeadREST dispõe de asserções. Estas asserções, semelhantes aos triplos de Hoare, são compostas por uma pré-condição, um URI template da operação e uma pós-condição. As asserções especificam que, quando a pré-condição é satisfeita, a execução da operação estabelece a pós-condição. Devido ao sistema de tipos refinados não é possível resolver através de regras sintácticas as relações de subtipagem. Para endereçar esta situação foi tomada a decisão de utilizar um procedimento semântico para tratar destas situações. A relação de subtipagem é transformada em fórmulas lógicas de primeira ordem, que são depois dadas a um SMT solver para as resolver. Apesar do seu grande poder expressivo, o HeadREST, como linguagem de especificação, está longe de ser perfeita. Um dos problemas mais importantes está relacionado com a sua usabilidade. Apesar da linguagem permitir descrever operações com grande rigor e detalhe, isso é feito à custa de asserções bastante complexas que são não só difíceis de escrever correctamente, como de compreender. Muitas das linguagens de especificação de serviços REST oferecem, mesmo que de forma limitada, uma forma de expressar o que o serviço exige em termos de autenticação e/ou autorização. Existem vários tipos de autenticação e autorização que podem ser usados para restringir acesso a recursos em serviços REST, por exemplo, API keys, Tokens, http authentication&HTTP digest, OAuth 2.0, OpenID Connect. Para além disto, cada serviço REST pode tomar abordagens diferentes em relação a políticas de autorização. Este trabalho endereçou estes dois problemas e pretendeu contribuir com soluções que os ajudassem a resolver. Para o problema de usabilidade, a solução concebida passou pela criação de extensões para a linguagem com ênfase em expressões derivadas. A linguagem foi estendida com: (i) iteradores quantificados que permitem expressar melhor propriedades sobre arrays, (ii) interpolação para permitir criar Strings a partir de URIs de uma forma mais simples e directa, (iii) um operador de extracção que permite aceder à representação de um recurso se esta for única e finalmente, (iv) funções que permitem abstrair expressões repetidas de uma forma mais flexível (apenas as funções não são derivadas). A abordagem para endereçar a especificação de políticas de segurança em APIs REST assentou na adição (i) de um novo tipo Principal, correspondente às entidades autenticadas e (ii) de uma função não-interpretada principalof capturando o Principal autenticado por um valor usado na autenticação. A linguagem foi estendida com a definição de funções não-interpretadas, para permitir que sejam feitas associações entre o tipo Principal e outros dados que possam vir de diferentes fontes (representações, templates de URIs, corpo dos pedidos, etc.), dando assim a possibilidade de especificar os diferentes tipos de políticas de segurança usadas em serviços REST. A avaliação das soluções propostas foi realizada de diferentes formas. Foi realizado um estudo com utilizadores envolvendo a resposta a um questionário com perguntas sobre a linguagem HeadREST antes e depois das extensões e foi feito um estudo quantitativo a comparar o impacto das extensões em termos de métricas de complexidade das especificações e no desempenho do validador. Para avaliar as extensões referentes à segurança foram realizados alguns casos de estudo, envolvendo a especificação parcial de alguns serviços REST do "mundo-real". Foi ainda explorado o impacto que as extensões introduzidas na linguagem têm nas ferramentas que actualmente fazem parte do ecossistema HeadREST: (i) a ferramenta HeadREST-RTester, que permite testar automaticamente a conformidade da implementação de um serviço REST contra uma especificação HeadREST da sua API, (ii) a ferramenta HeadREST-Codegen, que faz a geração de código, e (iii) a linguagem SafeRestScript, uma linguagem de script em que é realizada estaticamente a validação das chamadas a serviços REST cujas APIs tenham sido especificadas com HeadREST. A linguagem HeadREST possui um validador, um plug-in para o IDE Eclipse e uma versão headless para ser utilizada no terminal.The RESTful services are still today the most popular type of web services. Communication between these services and their clients happens through their RESTful APIs and, to correctly use the services, good documentation of their APIs is paramount. With the purpose of facilitating the specification of web APIs, different Interface Definition Languages (IDLs) have been developed. However, they tend to be quite limited and impose severe restrictions in what can be described. As a consequence, many important properties can only be written in natural language. HeadREST is a specification language of RESTful APIs that poses itself as a solution to the limitations faced by other IDLs. The language has an expressive type system via refinement types and supports the description of service endpoints through assertions that, among other things, allow to express relations between the information transmitted in a request and the response. HeadREST, like other IDLs, is however not without its limitations and issues. This thesis addresses the problems that currently affect the usability of HeadREST and also its lack of expressiveness for specifying security properties of RESTful APIs. The proposed solution encompasses (i) an extension of HeadREST with new specification primitives that can improve the degree of usability of the language and (ii) an ortogonal extension of HeadREST with specification primitives that support the description of authentication and authorisation policies for RESTful APIs. The evaluation of the proposed solution, performed through a user study, a quantitative analysis and the development of case studies, indicates that the primitives targeting the usability issues indeed improve usability of the language and that HeadREST become able to capture dynamic, state-based dependencies that exist in the access control policies that can be found in RESTful APIs

    Similar works